ES6提供了異步編程的幾個新特性:
本篇主要參考阮一峰大神的ES6文章。
Promise
1.基本用法:
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 異步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise構造函數接受一個函數,該函數的變量為resolve和reject,分別為兩個函數,作用為:resolve將promise對象的狀態變為resolved,reject將promise對象的狀態變為rejected。
Promise對象創建即執行:
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('Resolved.');
});
console.log('Hi!');
// Promise
// Hi!
// Resolved
2.Promise.prototype.then()方法
生成Promise對象后可通過then()方法來指定resolved、rejected狀態下的回調函數。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
2.Promise.prototype.catch()方法
是.then(null, rejection)的別名,用于指定發生錯誤時的回調函數。
用于獲取promise rejected狀態下的回調或者拋出異常。
Promise對象的錯誤狀態會一直向后傳遞直到被catch,但并不會被全局捕獲。
3.Promise.all()
用于將多個Promise實例,包裝成一個新的Promise實例。
var p = Promise.all([p1, p2, p3]);
- 只有p1、p2、p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。
- 只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
4.Promise.race()
同樣是將多個Promise實例,包裝成一個新的Promise實例。
var p = Promise.race([p1, p2, p3]);
只要p1、p2、p3之中有一個實例率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。
5.Promise.resolve()
將一個對象轉為Promise對象
6.Promise.reject()
將一個對象轉為Promise對象,狀態是rejected
Generator
generator函數類似于狀態機
1.基本用法
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
2.yield語句
調用generator函數,并不會立即執行,而必須要調用next方法,執行到generator函數中的yield語句后返回。
yield語句后的表達式作為函數返回值。
function* f() {
console.log('執行了!')
}
var generator = f();
setTimeout(function () {
generator.next()
}, 2000);
3.return方法
可以返回給定的值,并且終結遍歷Generator函數。
4.Generator函數與異步編程
可采用co模塊、thunk函數自動執行
ES7的async函數
就是 Generator 函數的語法糖
如Generator寫法:
var fs = require('fs');
var readFile = function (fileName) {
return new Promise(function (resolve, reject) {
fs.readFile(fileName, function(error, data) {
if (error) 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());
};
寫成async函數,就是下面:
var asyncReadFile = async function () {
var f1 = await readFile('/etc/fstab');
var f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
比較發現,async函數就是將 Generator 函數的星號(*)替換成async,將yield替換成await,僅此而已。
async函數對 Generator 函數的改進,體現在以下四點:
- 內置執行器
Generator 函數的執行必須靠執行器,所以才有了co模塊,而async函數自帶執行器。也就是說,async函數的執行,與普通函數一模一樣,只要一行。 - 更好的語義
async和await,比起*和yield,語義更清楚。async表示函數里有異步操作,await表示緊跟在后面的表達式需要等待結果。 - 更廣的適用性
co模塊約定,yield命令后面只能是 Thunk 函數或 Promise 對象,而async函數的await命令后面,可以是Promise 對象和原始類型的值(數值、字符串和布爾值,但這時等同于同步操作)。 - 返回值是 Promise
async函數的返回值是 Promise 對象,這比 Generator 函數的返回值是 Iterator 對象方便多了。你可以用then方法指定下一步的操作。