1. Promise用法详解
new Promise(
/* 执行器 executor */
function (resolve, reject) {
// 一段可能耗时很长的异步操作
doAsyncAction(function callback(err, result) {
if (err) {
return reject(err);
}
resolve(result);
});
}
)
.then(function resolve() {
// 成功,下一步
}, function reject() {
// 失败,做相应处理
});Promise 实例有三个状态:
pending[待定] 初始状态,新创建的实例处于这个状态fulfilled[实现] 操作成功,在执行器里调用resolve()之后,实例切换到这个状态rejected[被否决] 操作失败,在执行器里调用reject()之后,实例切换到这个状态
2. .then()
.then() 其实接受两个函数作为参数,分别代表 fulfilled 状态时的处理函数和 rejected 状态时的处理函数, .then() 会返回一个新的 Promise 实例,所以它可以链式调用,如前面的例子所示。当前面的 Promise 状态改变时,.then() 会执行特定的状态响应函数,并将其结果,调用自己的 Promise 的 resolve() 返回。
注意:Promise.resolve()在返回为null时,会返回一个状态为fulfilled的 Promise
几个例子:假定 doSomething() 和 doSomethingElse() 都会返回 Promise 对象
第一题
doSomething()
.then(function () {
return doSomethingElse();
})
.then(finalHandler);答案:
doSomething
|-----------|
doSomethingElse(undefined)
|------------|
finalHandler(resultOfDoSomethingElse)
|------------|
第二题
doSomething()
.then(function () {
doSomethingElse();
})
.then(finalHandler);答案:
doSomething
|-----------------|
doSomethingElse(undefined)
|------------------|
finalHandler(undefined)
|------------------|
这道题就有一定难度了。虽然 doSomethingElse 会返回 Promise 对象,但是因为 .then() 的响应函数并没有把它 return 出来,所以这里其实相当于 return null。我们知道,Promise.resolve() 在参数为空的时候会返回一个状态为 fulfilled 的 Promise,所以这里两步是几乎一起执行的。
第三题
doSomething()
.then(doSomethingElse())
.then(finalHandler);答案:
doSomething
|-----------------|
doSomethingElse(undefined)
|---------------------------------|
finalHandler(resultOfDoSomething)
|------------------|
这一题的语法陷阱也不小。首先,doSomethingElse 和 doSomethingElse() 的区别在于,前者是变量,指向一个函数;而后者是则是直接执行了函数,并返回其返回值。所以这里 doSomethingElse 立刻就开始执行了,和前面 doSomething 的启动时间相差无几,可以忽略不计。然后,按照 Promise 的设计,当 .then() 的参数不是函数的时候,这一步会被忽略不计,所以 doSomething 完成后就跳去执行 finalHandler 了。
第四题
doSomething()
.then(doSomethingElse)
.then(finalHandler);答案:
doSomething
|-----------|
doSomethingElse(resultOfDoSomething)
|------------|
finalHandler(resultOfDoSomethingElse)
|------------------|3. .catch()
使用方法:
doSomething()
.doAnotherThing()
.doMoreThing()
.catch( err => {
console.log(err);
});注意:
一旦resolve()方法中抛出了错误,会跳过后面.then(),进入.catch()处理异常。catch()后的.then()方法仍能继续执行。
new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
})
.then( () => {
console.log('start');
throw new Error('test error');
})
.catch( err => {
console.log('I catch: ', err);
// 下面这一行的注释将引发不同的走向
// throw new Error('another error');
})
.then( () => {
console.log('arrive here');
})
.then( () => {
console.log('... and here');
})
.catch( err => {
console.log('No, I catch: ', err);
});
// 输出:
// start
// I catch: test err
// arrive here
// ... and here4. Promise.all()
Promise.all(promiseArray)方法是Promise对象上的静态方法,该方法的作用是将多个Promise对象实例包装,生成并返回一个新的Promise实例。
var p1 = Promise.resolve(1),
p2 = Promise.resolve(2),
p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {
console.log(results); // [1, 2, 3]
});在上面的方法中,promise数组中所有的promise实例都变为resolve的时候,该方法才会返回,并将所有结果传递results数组中。promise数组中任何一个promise为reject的话,则整个Promise.all调用会立即终止,并返回一个reject的新的promise对象。reject使用示例如下:
var p1 = Promise.resolve(1),
p2 = Promise.reject(2),
p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {
//then方法不会被执行
console.log(results);
}).catch(function (e){
//catch方法将会被执行,输出结果为:2
console.log(e);
});5. Promise 实现队列
1. 使用 forEach
function queue(things) { let promise = Promise.resolve(); things.forEach(thing => { promise = promise.then(() => { return new Promise(resolve => { doThing(thing, () => { resolve(); }) }) }) })}
queue([1, 2, 3, 4]);2. 使用 reduce
function queue(things) { return things.reduce(promise, thing => { return promise.then(() => { return new Promise(resolve => { doThing(thing, () => { resolve(); }) }) }) }, Promise.resolve())}
queue([1, 2, 3, 4]);6. Promise.resolve()/reject()/race()使用
7. Promise兼容性问题
bluebird
promise polyfill
8. ES2017 async() 、await()
附录: