ES6知識點整理之----Generator----異步
所謂"異步",簡單說就是一個任務不是連續完成的,可以理解成該任務被人為分成兩段,先執行第一段,然後轉而執行其他任務,等做好了準備,再回過頭執行第二段。
1、異步編程的方法:
- 回調函數
- 事件監聽
- 發布/訂閱
- Promise 對象
- Generator函數
2、為什麽 Node 約定,回調函數的第一個參數,必須是錯誤對象err
(如果沒有錯誤,該參數就是null
)?
原因是執行分成兩段,第一段執行完以後,任務所在的上下文環境就已經結束了。在這以後拋出的錯誤,原來的上下文環境已經無法捕捉,只能當作參數,傳入第二段。
3、Promise 對象就是為了解決 “回調函數地獄”問題而提出的,不是新的語法功能,而是一種新的寫法。允許將回調函數的嵌套,改成鏈式調用。Promise 的最大問題是代碼冗余,原來的任務被 Promise 包裝了一下,不管什麽操作,一眼看去都是一堆then
4、Generator函數,它的奧妙就在其中的yield
命令,它是異步兩個階段的分界線。整個 Generator 函數就是一個封裝的異步任務,或者說是異步任務的容器。異步操作需要暫停的地方,都用yield
語句註明。
5、Generator 函數可以作為異步編程的完整解決方案,有3個特性
- 可以暫停執行和恢復執行
- 函數體內外的數據交換:
next
返回值的 value 屬性,是 Generator 函數向外輸出數據;next
方法還可以接受參數,向 Generator 函數體內輸入數據。 - 錯誤處理機制
6、異步任務的封裝
var fetch = require(‘node-fetch‘);//封裝 function* gen(){ var url = ‘https://api.github.com/users/github‘; var result = yield fetch(url); console.log(result.bio); } //執行 var g = gen(); var result = g.next(); result.value.then(function(data){ return data.json(); }).then(function(data){ g.next(data); });
Thunk 函數
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 函數替換的不是表達式,而是多參數函數,將其替換成一個只接受回調函數作為參數的單參數函數。
// 正常版本的readFile(多參數版本) fs.readFile(fileName, callback); // Thunk版本的readFile(單參數版本) var Thunk = function (fileName) { return function (callback) { return fs.readFile(fileName, callback); }; }; var readFileThunk = Thunk(fileName); readFileThunk(callback);
任何函數,只要參數有回調函數,就能寫成 Thunk 函數的形式。
Generator 函數的流程管理
var fs = require(‘fs‘); var thunkify = require(‘thunkify‘); var readFileThunk = thunkify(fs.readFile); var gen = function* (){ var r1 = yield readFileThunk(‘/etc/fstab‘); console.log(r1.toString()); var r2 = yield readFileThunk(‘/etc/shells‘); console.log(r2.toString()); }; var g = gen(); var r1 = g.next(); r1.value(function (err, data) { if (err) throw err; var r2 = g.next(data); r2.value(function (err, data) { if (err) throw err; g.next(data); }); });
Thunk 函數的自動流程管理
Thunk 函數真正的威力,在於可以自動執行 Generator 函數。
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(g);
跟在yield
命令後面的必須是 Thunk 函數。
var g = function* (){ var f1 = yield readFileThunk(‘fileA‘); var f2 = yield readFileThunk(‘fileB‘); // ... var fn = yield readFileThunk(‘fileN‘); }; run(g);
co 模塊
一個小工具,用於 Generator 函數的自動執行。
ES6知識點整理之----Generator----異步