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 here复制代码
4. 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()
附录: