详细参考:http://liubin.org/promises-book/#__5
新建一个promise对象:
要想创建一个promise对象、可以使用new
来调用Promise
的构造器来进行实例化。
var promise = new Promise(function(resolve, reject) {
// 异步处理
// 处理结束后、调用resolve 或 reject
});
Instance Method
对通过new生成的promise对象为了设置其值在 resolve(成功) /reject(失败)时调用的回调函数可以使用promise.then()
实例方法。
promise.then(onFulfilled, onRejected)
-
resolve(成功)时
-
onFulfilled
会被调用
reject(失败)时
-
onRejected
会被调用
onFulfilled
、onRejected
两个都为可选参数。
promise.then
成功和失败时都可以使用。另外在只想对异常进行处理时可以采用promise.then(undefined, onRejected)
这种方式,只指定reject时的回调函数即可。不过这种情况下promise.catch(onRejected)
应该是个更好的选择。
Static Method
像 Promise
这样的全局对象还拥有一些静态方法。
包括 Promise.all()
还有 Promise.resolve()
等在内,主要都是一些对Promise进行操作的辅助方法。
静态方法Promise.resolve(value)
可以认为是new Promise()
方法的快捷方式。
比如 Promise.resolve(42);
可以认为是以下代码的语法糖。
new Promise(function(resolve){
resolve(42);
});
在这段代码中的 resolve(42);
会让这个promise对象立即进入确定(即resolved)状态,并将42
传递给后面then里所指定的onFulfilled
函数。
方法 Promise.resolve(value);
的返回值也是一个promise对象,所以我们可以像下面那样接着对其返回值进行.then
调用。
Promise.resolve(42).then(function(value){
console.log(value);
});
Promise.all
接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then
方法。
数组里的方法会同时开始执行,而且每个promise的结果(resolve或reject时传递的参数值),和传递给Promise.all
的promise数组的顺序是一致的。
也就是说,这时候 .then
得到的promise数组的执行结果的顺序是固定的,即 [comment, people]。
接着我们来看看和 Promise.all
类似的对多个promise对象进行处理的 Promise.race
方法。
区别:
Promise.all
在接收到的所有的对象promise都变为 FulFilled 或者 Rejected 状态之后才会继续进行后面的处理,与之相对的是Promise.race
只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。
then(onFulfilled, onRejected)和catch的不同:
Deferred和Promise的关系
简单来说,Deferred和Promise具有如下的关系。
-
Deferred 拥有 Promise
-
Deferred 具备对 Promise的状态进行操作的特权方法
-
所谓的能对Promise状态进行操作的特权方法,指的就是能对promise对象的状态进行resolve、reject等调用的方法,而通常的Promise的话只能在通过构造函数传递的方法之内对promise对象的状态进行操作。
function Deferred() {
this.promise = new Promise(function (resolve, reject) {
this._resolve = resolve;
this._reject = reject;
}.bind(this));
}
Deferred.prototype.resolve = function (value) {
this._resolve.call(this.promise, value);
};
Deferred.prototype.reject = function (reason) {
this._reject.call(this.promise, reason);
};
function getURL(URL) {
var deferred = new Deferred();
var req = new XMLHttpRequest();
req.open('GET', URL, true);
req.onload = function () {
if (req.status === 200) {
deferred.resolve(req.responseText);
} else {
deferred.reject(new Error(req.statusText));
}
};
req.onerror = function () {
deferred.reject(new Error(req.statusText));
};
req.send();
return deferred.promise;
}
// 运行示例
var URL = "http://httpbin.org/get";
getURL(URL).then(function onFulfilled(value){
console.log(value);
}).catch(console.error.bind(console));
我们发现它们有如下不同。
-
Deferred 的话不需要将代码用Promise括起来
-
由于没有被嵌套在函数中,可以减少一层缩进
-
反过来没有Promise里的错误处理逻辑
-
在以下方面,它们则完成了同样的工作。
-
整体处理流程
-
调用
resolve
、reject
的时机
-
-
函数都返回了promise对象
由于Deferred包含了Promise,所以大体的流程还是差不多的,不过Deferred有用对Promise进行操作的特权方法,以及高度自由的对流程控制进行自由定制。
比如在Promise一般都会在构造函数中编写主要处理逻辑,对 resolve
、reject
方法的调用时机也基本是很确定的。
new Promise(function (resolve, reject){
// 在这里进行promise对象的状态确定
});
而使用Deferred的话,并不需要将处理逻辑写成一大块代码,只需要先创建deferred对象,可以在任何时机对 resolve
、reject
方法进行调用。
var deferred = new Deferred();
// 可以在随意的时机对 `resolve`、`reject` 方法进行调用
换句话说,Promise代表了一个对象,这个对象的状态现在还不确定,但是未来一个时间点它的状态要么变为正常值(FulFilled),要么变为异常值(Rejected);而Deferred对象表示了一个处理还没有结束的这种事实,在它的处理结束的时候,可以通过Promise来取得处理结果。
如果各位读者还想深入了解一下Deferred的话,可以参考下面的这些资料。
什么是 Promise.prototype.done ?
如果你使用过其他的Promise实现类库的话,可能见过用done
代替then
的例子。
这些类库都提供了 Promise.prototype.done
方法,使用起来也和 then
一样,但是这个方法并不会返回promise对象。
使用Done例子
if (typeof Promise.prototype.done === 'undefined') {
Promise.prototype.done = function (onFulfilled, onRejected) {
this.then(onFulfilled, onRejected).catch(function (error) {
setTimeout(function () {
throw error;
}, 0);
});
};
}
var promise = Promise.resolve();
promise.done(function () {
JSON.parse('this is not json'); // => SyntaxError: JSON.parse
});
从上面我们可以看出,两者之间有以下不同点。
-
done
并不返回promise对象-
也就是说,在done之后不能使用
catch
等方法组成方法链
-
-
done
中发生的异常会被直接抛给外面-
也就是说,不会进行Promise的错误处理(Error Handling)
-
由于done
不会返回promise对象,所以我们不难理解它只能出现在一个方法链的最后。
使用Promise进行顺序(sequence)处理
另外提供promise扩展模块Q模块的方法大全文档:https://github.com/kriskowal/q/wiki/API-Reference
bluebird模块:http://bluebirdjs.com/docs/api-reference.html