摘要:總結本文簡要介紹了函數的一些特性,重點在于說明如何使用函數對異步任務進行封裝,從而能夠讓異步代碼編寫的更加清晰。
在之前的文章介紹了傳統異步的實現方案,本文將介紹ES6中的一種全新的異步方案--Generator函數。
generator簡介簡單介紹一下generator的原理和語法,(更詳細內容請看ECMAScript 6 入門,本文只介紹和異步相關的核心內容)
基本語法通過一個簡單的例子來了解generator函數
function* MyGenerator() { yield "yield的含義是:執行此處時,暫停執行當前函數" yield "暫停之后的函數可以用next方法繼續執行" return "遇到return之后會真正結束,done會變成true" } const gen = MyGenerator() //執行后返回的是一個指針,可以利用該指針執行next方法 console.log(gen.next()) // {value: "yield的含義是:執行此處時,暫停執行當前函數“, done: false} console.log(gen.next())// {value: "暫停之后的函數可以用next方法繼續執行", done: false} console.log(gen.next())// {value: "遇到return之后會真正結束,done會變成true", done: true}數據交互
數據交互指的是可以通過yield把當前執行的結果傳出,也可以使用next把外部參數傳入
function* MyGenerator(){ const result = yield "傳出的數據" return result } const gen = MyGenerator() console.log(gen.next())// generatorAndAsync2.html:19 {value: "傳出的數據", done: false} console.log(gen.next("傳入的數據"))// {value: "傳入的數據", done: true}
交互的參數類型當然也可以是函數:
function sayHi(){ console.log("hi"); } function* MyGenerator(){ const result = yield sayHi() return } const gen = MyGenerator() const result = gen.next()// {value: sayHi, done: false} result.value() // 正常輸出"hi"
具備以上最核心的兩個特性之后,generator就可以進行異步操作封裝。
異步任務封裝首先,結合異步任務的特點以及前文提到的genrator函數的特性,提煉出使用generator封裝異步操作的核心思路:
在異步任務執行時,使用yield交出執行權
在異步任務結束后,使用next交還執行權
起步從一個最簡單的例子開始:
// 1. 首先寫一個異步任務,在一秒后返回特定字符串 function asyncTask(callback){ setTimeout(()=>{ callback("Hello Leo") }, 1000) } // 2. 接下來寫出期望執行的順序 function* runTask() { let text = yield asyncTask console.log(text) // 我們期望這里正常輸出Hello Leo } // 3. 按照期望值執行函數 const gen = runTask()// 此時執行權已經交出 gen.next().value(function (text) {// 執行asyncTask并傳入callback ,關鍵點在于在callback里調用next交還執行權 gen.next(text) })
首先,這段代碼雖然很粗糙,但是已經反映了使用generator封裝異步任務的核心思想。最直觀的受益就是:runTask的內容看起來很像同步代碼,條理清晰,很適合閱讀。
但是上面第3部分關于執行的代碼很不靈活,我們不能每次都這么寫一段,因此接下來的目標就是實現一個任務執行器。
自動任務執行器同樣的,先思考核心的思路:要想讓某個generator函數自動執行,無非就是一個while循環:
1. 如果當前yield返回值的done屬性為true,說明任務已經執行完成; 2. 如果當前yield返回值的done屬性為false,說明任務還未執行完成,則繼續執行next,同時要注意參數傳遞
根據分析實現以下的執行器:
function autoExecute(task) { const gen = task() let result = gen.next() while(true){ if(result.done){ break // 執行結束 return } console.log(result.value)//為了便于觀察 我們加上console.log result = gen.next(result.value) // 每次都應該重寫result 獲取最新結果 } } function* simpleTask(){ yield 1 yield 2 yield 3 return } autoExecute(simpleTask)// 測試我們寫的自動執行器 能夠正確輸出123
上面的執行器已經有了雛形,但是對于前面例子中,result.value為函數的情況還沒有處理,因此還需要稍微補充:
function isFunction(source){ return Object.prototype.toString.call(source) === "[object Function]" } function autoExecute(task) { const gen = task() let result = gen.next() let isRuningAsync = false // 由于加入了異步處理,所以要增加一個標志位避免重復進入循環體 while (!isRuningAsync) { if (result.done) { return } console.log(result.value) /* start 補充的處理函數 */ if (isFunction(result.value)) { isRuningAsync = true const callback = (arg) => { result = gen.next(arg) // 核心代碼 isRuningAsync = false } result.value(callback) /* end 補充的處理函數 */ } else { result = gen.next(result.value) } } } autoExecute(runTask) // 試著用這個自動執行器執行之前的異步任務
上面這個自動執行器,就完成了generator對異步任務的封裝。
總結本文簡要介紹了generator函數的一些特性,重點在于說明如何使用generator函數對異步任務進行封裝,從而能夠讓異步代碼編寫的更加清晰。
再次強調:用generator函數對異步任務封裝的思想是很明確的--控制 Generator 函數的流程,在適當的時機接收和交還程序的執行權,但是具體的實現方式并不唯一,例如本文用的是最簡單直接的回調函數方式,在阮一峰老師的《es6入門》教程里,也有使用thunk思路來講解的部分,可以自行查閱。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109850.html
摘要:前文該系列下的前幾篇文章分別對不同的幾種異步方案原理進行解析,本文將介紹一些實際場景和一些常見的面試題。流程調度里比較常見的一種錯誤是看似串行的寫法,可以感受一下這個例子判斷以下幾種寫法的輸出結果辨別輸出順序這類題目一般出現在面試題里。 前文 該系列下的前幾篇文章分別對不同的幾種異步方案原理進行解析,本文將介紹一些實際場景和一些常見的面試題。(積累不太夠,后面想到再補) 正文 流程調度...
摘要:在誕生以前,異步編程的方式大概有下面四種回調函數事件監聽發布訂閱對象將異步編程帶入了一個全新的階段,中的函數更是給出了異步編程的終極解決方案。這意味著,出錯的代碼與處理錯誤的代碼,實現了時間和空間上的分離,這對于異步編程無疑是很重要的。 寫在前面 有一個有趣的問題: 為什么Node.js約定回調函數的第一個參數必須是錯誤對象err(如果沒有錯誤,該參數就是null)? 原因是執行回調函...
摘要:回調函數這是異步編程最基本的方法。對象對象是工作組提出的一種規范,目的是為異步編程提供統一接口。誕生后,出現了函數,它將異步編程帶入了一個全新的階段。 更多詳情點擊http://blog.zhangbing.club/Ja... Javascript 語言的執行環境是單線程的,如果沒有異步編程,根本沒法用,非卡死不可。 為了解決這個問題,Javascript語言將任務的執行模式分成兩種...
摘要:接下來我們看下三類異步編程的實現。事件監聽事件發布訂閱事件監聽是一種非常常見的異步編程模式,它是一種典型的邏輯分離方式,對代碼解耦很有用處。 一、 一道面試題 前段時間面試,考察比較多的是js異步編程方面的相關知識點,如今,正好輪到自己分享技術,所以想把js異步編程學習下,做個總結。下面這個demo 概括了大多數面試過程中遇到的問題: for(var i = 0; i < 3; i++...
摘要:回調函數這是最原始的一種異步解決方法。從的對象演化而來對象是提出的一種對異步編程的解決方案,但它不是新的語法,而是一種新的寫法,允許將回調函數的嵌套改成鏈式調用。 一、前言 異步編程對JavaScript來說非常重要,因為JavaScript的語言環境是單線程的,如果沒有異步編程將變得非常可怕,估計根本無法使用。這篇文章就來總結一下從最原始的回調函數到現在的ES6、ES7的新方法。 文...
閱讀 688·2023-04-25 19:53
閱讀 4261·2021-09-22 15:13
閱讀 2565·2019-08-30 10:56
閱讀 1320·2019-08-29 16:27
閱讀 2931·2019-08-29 14:00
閱讀 2407·2019-08-26 13:56
閱讀 426·2019-08-26 13:29
閱讀 1611·2019-08-26 11:31