在最開始的時候,js非同步程式設計是一件很痛苦的事,不過隨著技術發展,現在寫非同步已經可以像寫同步一樣舒服了。
主要的變化過程:
回撥函式 ===>>> promise ===>>> generater ===>>> async/await
回撥函式時代
dosomething(sucessCallback, errCallback)
複製程式碼
這種寫法在多重非同步處理的時候很容易出現回撥地獄
promise寫法
promise最大的好處就是實現了鏈式呼叫的寫法,而且可以用catch來捕獲異常。
不過Promise 物件的錯誤具有“冒泡”性質,會一直向後傳遞,直到被捕獲為止;而且promise會吞掉錯誤,不向外部丟擲
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log(`Contents: ` + json);
}).catch(err => console.log(err));
複製程式碼
generator寫法
Generator 函式是協程在 ES6 的實現,最大特點就是可以交出函式的執行權,注意它不是語法糖。
- 第一步,協程A開始執行。
- 第二步,協程A執行到一半,進入暫停,執行權轉移到協程B。
- 第三步,(一段時間後)協程B交還執行權。
- 第四步,協程A恢復執行。
function* gen(x) {
var y = yield x + 2;
return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }
g.throw(`出錯了`);
複製程式碼
yield之後的跟隨的物件或基本型別的值會被自動轉化為promise。
generator最麻煩的就是需要自己執行next去執行下一步
async/await 寫法
這是generator+co庫的一個es7語法糖,最接近同步的語法。
由於generator需要不斷地執行,於是有人寫了一個叫co的自執行函式庫。
var co = require(`co`);
co(gen);
複製程式碼
這樣generator就可以自動地執行了。於是就出現了async/await的寫法:
async function getStockPriceByName(name) {
const symbol = await getStockSymbol(name);
const stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName(`goog`).then(function (result) {
console.log(result);
});
複製程式碼
async後面的函式返回的是一個promise物件,可以用.then的語法。
try {
getStockPriceByName()
} catch(err) {
console.log(error)
} finally {
dosomething()
}
複製程式碼
錯誤處理方面也更加接近同步的語法。
總結
只要能夠寫es6語法,我們就可以用上async/await的語法來解決非同步程式設計的需要了,這是將會是相當方便的一個體驗,也會給後續的人一個更清晰的程式碼邏輯。