目錄git
1.異步編程樣例es6
樣例:github
// 等待執行函數 function sleep(timeout) { return new Promise((resolve) => { setTimeout(resolve, timeout) }) } // 異步函數 async function test() { console.log('test start') await sleep(1000) console.log('test end') } console.log('start') test() console.log('end')
執行結果:編程
start test start end test end
2.樣例解析promise
在樣例代碼中,test
異步函數使用了async
和await
語法,這是ES2017裏面的異步編程規範。而爲了在較低版本的瀏覽器或Node支持這種語法,其中一種解決方案是將其轉化爲Generator
函數和Promise
來實現。換句話說,任何的async
和await
實現的異步函數,均可以替換成Generator
函數和Promise
實現。瀏覽器
第一步:先將async
和await
語法替換爲相應的Generator
函數,以下異步
// 代碼結構徹底一致,只是替換了對應關鍵字 function *test() { console.log('test start') yield sleep(1000) console.log('test end') }
第二步:爲了執行Generator
函數,使用Promise
實現一個自動執行器
函數 spawn
async
function spawn(genF) { return new Promise(function(resolve, reject) { const gen = genF(); function step(nextF) { let next; try { next = nextF(); } catch(e) { return reject(e); } if(next.done) { return resolve(next.value); } Promise.resolve(next.value).then(function(v) { step(function() { return gen.next(v); }); }, function(e) { step(function() { return gen.throw(e); }); }); } step(function() { return gen.next(undefined); }); }); }
第三步:將相應的Generator
函數和自動執行器
函數相結合,便可得最終的等價代碼異步編程
function asyncTest() { spawn(test) } console.log('start') asyncTest() console.log('end')
第四步:執行結果,與原來的一致函數
start test start end test end
第五步:分析asyncTest
函數執行過程
spawn(test)
,進入spawn
函數中,建立一個Promise並返回。 const gen = genF()
,獲取一個狀態機。(Generator 函數是一個狀態機,封裝了多個內部狀態。)step(function() { return gen.next(undefined); })
, 進入step
函數中。next = nextF()
,next
等於gen.next(undefined)
的返回結果。
gen.next(undefined)
開始執行,狀態機第一次調用,直到遇到第一個yield
表達式爲止,即yield sleep(1000)
,此時控制檯先輸出"test start",而且返回第一個狀態{ value: reuslt, done: false }
, 而 reuslt等於sleep(1000)
返回的結果,其是一個Promise。if(next.done)
,此時第一個狀態的done
爲false
,因此不執行if
語句裏面,繼續往下執行。Promise.resolve(next.value)
,因爲第一個狀態的value
是一個Promise
,因此直接返回其自己,也就至關於執行sleep(1000).then(...)
,sleep函數異步等待1秒後,resolve
接受的值爲undefined
,繼續執行then方法。step(function() { return gen.next(v); })
,此時v
爲undefined
,再次進入step
函數中。next = nextF()
,next
等於gen.next(undefined)
的返回結果。
gen.next(undefined)
再次執行時,狀態機第二次調用,此時Generator函數已經執行完畢,此時控制檯先輸出"test end",而且返回最後的狀態{ value: undefined, done: true }
if(next.done)
,此時第一個狀態的done
爲true
,因此執行if
語句裏面。return resolve(next.value)
,此時最初的Promise成功執行。asyncTest
函數執行結束。3.淺談Promise如何實現異步執行
從上述樣例解析中能夠看出,咱們是用Promise來實現代碼的異步執行,那Promise的內部是如何實現異步執行的呢?
經過查看Promise
的源碼實現,發現其異步執行是經過asap這個庫來實現的。
asap
是as soon as possible
的簡稱,在Node和瀏覽器環境下,能將回調函數以高優先級任務來執行(下一個事件循環以前),即把任務放在微任務隊列中執行。
宏任務(macro-task)和微任務(micro-task)表示異步任務的兩種分類。在掛起任務時,JS 引擎會將全部任務按照類別分到這兩個隊列中,首先在 macrotask 的隊列(這個隊列也被叫作 task queue)中取出第一個任務,執行完畢後取出 microtask 隊列中的全部任務順序執行;以後再取 macrotask 任務,周而復始,直至兩個隊列的任務都取完。
用法:
asap(function () { // ... });
4.參考