es6 Promise

Promise含义

  • Promise 对象,用来传递异步操作的消息。代表了某个未来才会知道结果的事件(通常是一个异步操作)。这个事件提供统一的API,可供进一步处理
  • 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易
  • 无法取消Promise。如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

基本用法

Promise实例:

1
2
3
4
5
6
7
8
9
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});

resolve和reject是两个函数,由JavaScript引擎提供

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function test(object) {
return new Promise((resolve, reject) => {
//resolve("success");
reject("error");
});
}
test().then((value) => {
//resolve
console.log(value);
},function(value){
//reject
console.log(value);
});

then()–Promise.prototype.then()

  • Promise实例有then方法,then方法定义在原型对象Promise.prototype上.返回的是一个新的Promise实例
  • 可以采用链式(chain)写法,即then方法后面再调用另一个then方法,后一个then的回调函数,会等待新Promise对象的状态发生变化,才会被调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function funcA(comments) {
console.log("Resolved: ", comments);
}, function funcB(err){
console.log("Rejected: ", err);
});
// 第二个then的回调函数,会等待这个新的Promise对象状态发生变化。如果变为Resolved,就调用funcA
function(post) {
return getJSON(post.commentURL);
}
//等于
post => getJSON(post.commentURL)

catch()–Promise.prototype.catch()

建议总是使用catch方法,而不使用then方法的第二个参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});

catch方法返回的还是一个Promise对象,因此后面还可以接着调用then方法。

如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应

有必要时,可以在回调链最后加done(),保证抛出任何可能出现的错误

Promise.all()

用于将多个Promise实例,包装成一个新的Promise实例。适合用于事务

p的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

1
2
3
4
5
6
7
8
9
10
// 生成一个Promise对象的数组
var promises = [2, 3, 5, 7, 11, 13].map(function(id){
return getJSON("/post/" + id + ".json");
});
Promise.all(promises).then(function(posts) {
// ...
}).catch(function(reason){
// ...
});

Promise.race()

同样是将多个Promise实例,包装成一个新的Promise实例。可用于超时判断 setTimeout
超时判断可用bluebird的.timeout(
int ms,
[String message=”operation timed out”]
) -> Promise

只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的回调函数

1
2
3
4
5
6
7
8
var p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
])
p.then(response => console.log(response))
p.catch(error => console.log(error))
  • bluebird Promise.some 可以传入count,来确定返回几个,promise.any则返回一个
1
2
3
4
5
6
7
8
Promise.some([
ping("ns1.example.com"),
ping("ns2.example.com"),
ping("ns3.example.com"),
ping("ns4.example.com")
], 2).spread(function(first, second) {
console.log(first, second);
});

Promise.resolve()

将现有对象转为Promise对象

参数是一个Promise实例,将不做变动的返回

参数是thenable对象 将这个对象转为Promise对象,然后就立即执行thenable对象的then方法

参数是一个原始值,或者是一个不具有then方法的对象 返回一个新的Promise对象,状态为Resolved

不带有任何参数 直接返回一个Resolved状态的Promise对象

1
2
3
4
5
6
7
8
9
10
11
12
13
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three

Promise.resolve()在本轮“事件循环”(event loop)结束时执行,setTimeout(fn, 0)在下一轮“事件循环”开始时执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//无论执行失败还是成功 最后都会回调,依照nodejs回调规范,第一个参数error,第二个成功结果。
bluebird .asCallback(
[function(any error, any value) callback],
[Object {spread: boolean=false} options]
) -> this
//spread 用于遍历拆分数组
Promise.resolve([1,2,3]).asCallback(function(err, a, b, c) {
// err == null
// a == 1
// b == 2
// c == 3
}, {spread: true});