目錄
一、async和await是什么
ES2017 標准引入了 async 函數,使得異步操作變得更加方便,async其實本質是Generator函數的語法糖
- async表示函數里有異步操作
- await表示在后面的表達式需要等待結果
- async函數返回的是一個Promise對象,可以使用then方法添加回調函數,一旦遇到await就會先返回。
二、node異步編程演進的四個階段
我們來回顧一下異步編程的寫法的演進過程
第1階段 通過回調函數
fs.readFile('/etc/passwd', 'utf-8', function (err, data) {
if (err) throw err;
console.log(data);
})
這樣的方式會造成嵌套過多,在調用過多的時候,就變成了下面這樣的寫法,傳說中的callback hell
fs.readFile(fileA, 'utf-8', function (err, data) {
fs.readFile(fileB, 'utf-8', function (err, data) {
fs.readFile(fileC, 'utf-8', function (err, data) {
// ...
});
});
});
第2階段 通過Promise
Promise 對象允許將回調函數的嵌套,改成鏈式調用。
采用 Promise,連續讀取多個文件,寫法如下。
const readFile = function (fileName) {
return new Promise(function (resolve, reject) {
fs.readFile(fileName, function(error, data) {
if (error) return reject(error);
resolve(data);
});
});
};
當操作很多的時候就變成了下面這樣的寫法
var readFile = require('fs-readfile-promise');
readFile(fileA)
.then(function (data) {
console.log(data.toString());
})
.then(function () {
return readFile(fileB);
})
.then(function (data) {
console.log(data.toString());
})
.catch(function (err) {
console.log(err);
});
這樣雖然比callback好了,但是有一個問題是代碼冗余,不管什么操作,看上去都是一堆then
第3階段 通過Generator函數
function* asyncJob() {
// ...其他代碼
var f = yield readFile(fileA);
// ...其他代碼
}
函數asyncJob是一個協程,協程遇到yield命令就暫停,等到執行權返回,再從暫停的地方繼續往后執行,這樣的寫法非常像同步操作。
要想使用yield方法,得不停地執行next()切換到下一個yeild,調用變成了下面這樣
var fs = require('fs');
var readFile = function (fileName){
return new Promise(function (resolve, reject){
fs.readFile(fileName, function(error, data){
if (error) return reject(error);
resolve(data);
});
});
};
var gen = function* (){
var f1 = yield readFile('/etc/fstab');
var f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
第4階段 通過async和await
async 函數本質就是 Generator 函數的語法糖
最后演變成了下面這樣的寫法
const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
async和await,比起*和yield,語義更清楚了。
async表示函數里有異步操作,await表示在后面的表達式需要等待結果
async函數的返回值是Promise對象
await后面,可以是Promise對象和原始類型的值(數值、字符串和布爾值,會自動轉換成resolved的Promise對象)