Promise入门

1 什么是Promise

promise是一种异步编程的解决方案,因为正常写回调很不直观,嵌套多了之后简直令人崩溃,所以有了promise这个东西。ES6则是将promise进行了统一,提供了原生的promise对象。

2 基本用法

1
2
3
4
5
6
7
8
var promise = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('ok');
}, 3000);
});
promise.then(function(value){
console.log(value);
});

3 接口

3.1 then()

then() 的作用是为Promise对象增加回调函数,第一个参数是Resolced状态的回调函数,第二个参数可选,是Rejected状态的回调函数,then() 返回的是一个新的Promise对象,所以后面还可以继续写then();

1
2
3
4
5
6
7
8
9
10
11
12
13
var getPromise = function(num){
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(num);
}, 3000);
});
}
getPromise(1).then(function(value){
console.log(value);
return getPromise(2)
}).then(function(value){
console.log(value);
})

输出结果是

1

2

3.2 catch()

catch() 方法和 then(null,rejection) 方法是等价的,都是指定promise对象发生错误时的回调函数。

1
2
3
4
5
6
7
var promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise.catch(function(error) {
console.log(error);
});
// Error: test

1
2
3
4
5
6
var promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});

上面两种写法是等价的。

==需要注意的是如果Promise对象的状态已经变成Resolved那么再抛出错误是无效的==。

3.3 all()

Promise.all() 方法用于将多个Promise实例包装成一个新的Promise实例。

1
var p = Promise.all([p1, p2, p3]);

all() 方法的参数是数组或者是具有Iterator的对象且每个成员的返回值都是Promise实例。
all方法的最终状态可以参考

  • 只有每个成员的状态都变成 fulfilledp 的状态才会变成 fulfilled;
  • 而成员的状态有一个变成 rejectedp 的状态就会变成 rejected;

3.4 race()

race() 方法同样是将多个Promise实例包装成一个新的Promise实例。
all() 不同的是,他的成员中有一个状态改变,那么新的Promise状态就会跟着改变

1
2
3
4
5
6
7
8
var p = Promise.race([
fetch('...'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
])
p.then(response => console.log(response))
p.catch(error => console.log(error))

看上面的例子,如果5s后fetch没有返回结果,那么后面的第二个Promise成员就会改变状态为 rejected ,那么p的状态就变成了 rejected ,然后就会触发catch的回调函数。

3.5 resolved()

resolved() 的作用是将现有的对象转换成Promise对象。

1
2
3
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

参数分为4种情况:

  1. 参数是一个Promise对象,那么这时候就会原封不动地返回这个对象
  2. 一个thenable对象(带有then方法的对象)

    1
    2
    3
    4
    5
    var thenable = {
    then: function(resolve, reject) {
    resolve();
    }
    };

    resolve方法会将这个对象转换为新的Promise 对象并且立即执行then方法

  3. 参数不是then方法的对象,或者根本不是对象,则resolved的方法返回一个新的promise对象,状态为Resolved

    1
    2
    3
    4
    5
    6
    var p = Promise.resolve('Hello');
    p.then(function (s){
    console.log(s)
    });
    // Hello
  4. 参数为空:直接返回一个Resolved状态的Promise对象。

3.6 reject()

reject()方法也会返回一个新的Promise实例,该实例的状态为rejected。它的参数用法与Promise.resolve方法完全一致。

1
2
3
4
5
6
7
8
var p = Promise.reject('出错了');
// 等同于
var p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s){
console.log(s)
});
// 出错了

3.7 done()

如果回调链的最后一个方法发生错误,那么就无法捕捉,所以提供了done()方法,放在回调链最后,捕捉最后可能出现的错误。

3.8 finally

finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。

4 Promise使用案例(实现fs.unlink方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// unlink(path).then()
var unlink = (path) => {
return new Promise((resolve, reject) => {
fs.unlink(path, function(err) {
if (err) {
reject(err);
} else {
resolve()
}
});
})
}
var unlinkAll = (pathList) => {
var promiseList = [];
for (var path of pathList) {
promiseList.push(unlink(path));
}
return Promise.All(promiseList);
}