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方法指定下一步的操作。