異步編程 :
(異步編程的語法目的就是讓異步編程更像同步編程)
回調(diào)函數(shù)
利用回調(diào)函數(shù)實現(xiàn)異步編程本身沒有問題, 問題在于回調(diào)函數(shù)的嵌套過多, 就會進入可怕的回調(diào)地獄.事件監(jiān)聽
發(fā)布訂閱
Promise
是一種新的寫法,允許將回調(diào)函數(shù)的橫向加載,改成縱向加載, 但是代碼過長也會看起來語義不清晰
其實我覺得promise挺好了...大概是我太年輕
ES6異步編程:
協(xié)程: 多個線程互相協(xié)作,完成異步任務
第一步,協(xié)程A開始執(zhí)行。
第二步,協(xié)程A執(zhí)行到一半,進入暫停,執(zhí)行權轉(zhuǎn)移到協(xié)程B。
第三步,(一段時間后)協(xié)程B交還執(zhí)行權。
第四步,協(xié)程A恢復執(zhí)行。
Generator函數(shù)
Generator 函數(shù)就是協(xié)程在 ES6 的實現(xiàn),最大特點就是可以交出函數(shù)的執(zhí)行權(即暫停執(zhí)行)。
整個 Generator 函數(shù)就是一個封裝的異步任務,或者說是異步任務的容器。函數(shù)名之前要加星號, 異步操作需要暫停的地方,都用 yield 語句注明。
function* gen(x){
var y = yield x + 2;
return y;
}
Generator函數(shù)的執(zhí)行 :
var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }
上面代碼中,調(diào)用 Generator 函數(shù),會返回一個內(nèi)部指針g(即遍歷器) 。這是 Generator 函數(shù)不同于普通函數(shù)的另一個地方,即執(zhí)行它不會返回結(jié)果,返回的是指針對象。調(diào)用指針 g 的 next 方法,會移動內(nèi)部指針(即執(zhí)行異步任務的第一段),指向第一個遇到的 yield 語句,上例是執(zhí)行到 x + 2 為止。換言之,next 方法的作用是分階段執(zhí)行 Generator 函數(shù)。每次調(diào)用 next 方法,會返回一個對象,表示當前階段的信息( value 屬性和 done 屬性)。value 屬性是 yield 語句后面表達式的值,表示當前階段的值;done 屬性是一個布爾值,表示 Generator 函數(shù)是否執(zhí)行完畢,即是否還有下一個階段。
Generator 函數(shù)的數(shù)據(jù)交換和錯誤處理
Generator 函數(shù)可以暫停執(zhí)行和恢復執(zhí)行,這是它能封裝異步任務的根本原因。它還有兩個特性,使它可以作為異步編程的完整解決方案:函數(shù)體內(nèi)外的數(shù)據(jù)交換和錯誤處理機制。
next 方法返回值的 value 屬性,是 Generator 函數(shù)向外輸出數(shù)據(jù);next 方法還可以接受參數(shù),這是向 Generator 函數(shù)體內(nèi)輸入數(shù)據(jù)。
Generator 函數(shù)內(nèi)部還可以部署錯誤處理代碼,捕獲函數(shù)體外拋出的錯誤。
function* gen(x){
try {
var y = yield x + 2;
} catch (e){
console.log(e);
}
return y;
}
var g = gen(1);
g.next();
g.throw('出錯了');
// 出錯了
上面代碼的最后一行,Generator 函數(shù)體外,使用指針對象的 throw 方法拋出的錯誤,可以被函數(shù)體內(nèi)的 try ... catch 代碼塊捕獲。這意味著,出錯的代碼與處理錯誤的代碼,實現(xiàn)了時間和空間上的分離。
Generator 函數(shù)的用法
var fetch = require('node-fetch');
function* gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
上面代碼中,Generator 函數(shù)封裝了一個異步操作,該操作先讀取一個遠程接口,然后從 JSON 格式的數(shù)據(jù)解析信息。就像前面說過的,這段代碼非常像同步操作,除了加上了 yield 命令。
var g = gen();
var result = g.next();
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data);
});
首先執(zhí)行 Generator 函數(shù),獲取遍歷器對象,然后使用 next 方法,執(zhí)行異步任務的第一階段。由于Fetch 模塊返回的是一個 Promise 對象,因此要用 then 方法調(diào)用下一個next 方法。