本系列屬於阮一峯老師所著的ECMAScript 6 入門學習筆記javascript
ES6以前,異步編程的方法,大概有下面四種:java
Generator函數將JavaScript異步編程帶入了一個全新的階段es6
傳統的編程語言,早有異步編程的解決方案,即多任務解決方案。其中一種叫"攜程"(coroutine),意思是多線程相互協做,完成異步任務編程
// yield命令成爲異步兩個階段的分界線,利用yield暫停任務,進行異步操做 function* asyncJob(){ // ...其餘代碼 var f= yield readFile(fileA) // ...其餘代碼 }
Generator函數能夠暫停執行和恢復執行,這是它能封裝異步任務的根本緣由。除此以外,它還有兩個特性能夠做爲異步編程的完美解決方案:函數體內外數據交換和錯誤處理機制多線程
// next返回值的value屬性,是Generator函數向外輸出的數據;next還能夠接收參數,向Generator函數體內輸入數據 function* gen(x){ var y = yield x + 2 return y } var g = gen(1) g.next() // {value:3,done:false} g.next(2) // {value:2,done:false} // Generator函數內部能夠部署錯誤處理代碼,捕獲函數體外拋出的錯誤 function* gen(x){ try{ var y = yield x + 2 }catch(e){ console.log(e) } return y } var g = gen(1) g.next() g.throw('出錯了') // 出錯了
Thunk函數是自動執行Generator函數的一種方法。編譯器「傳名調用」實現,每每是將參數放在一個臨時函數中,再將這個臨時函數傳入函數體,這個臨時函數就是Thunk函數異步
function f(m){ return m * 2 } f(x+5) // 等同於 var thunk = function(){ return x + 5 } function f(thunk){ return thunk() * 2 }
JavaScript語言是傳值調用,它的Thunk函數含義有所不一樣。在JavaScript語言中,Thunk函數替換的不是表達式,而是多參數函數,將其替換成一個接受回調函數做爲參數的單參數函數async
// 正常多參數數版本函數 fs.readFile(fileName,callback) // Thunk版本單參數函數 var Thunk = function(fileName){ return function(callback){ return fs.readFile(fileName,callback) } } var readFileThunk = Thunk(fileName) readFileThunk(callback) // 任何函數,只要參數又回調函數,就能寫成Thunk函數的形式 const Thunk = function(fn){ return function(...args){ return function(callback){ return fn.call(this,...args,callback) } } } // 利用以上轉換器,生成f的Thunk函數 function f(a,cb){ cb(a) } const ft = Thunk(f) ft(1)(console.log) // 1
Thunk函數如今能夠用於Generator函數的自動流程管理。但Thunk函數並非Generator函數自動執行的惟一方案。由於自動執行的關鍵是,必須有一種機制,自動控制Generator函數的流程,接收和交還程序的執行權。回調函數能夠作到,Promise對象也能夠作到編程語言
function run(fn){ var gen = fn() function next(err,data){ var result = gen.next(data) if(result.done) return result.value(next) } next() } function* g(){ // ... } // run函數是一個Generator函數的自動執行器,next函數是Thunk的回調函數,result.value就是Thunk函數 run(g)