基础
ES6原生提供了Promise
对象,用来保存某个异步操作的结果。其状态不受外界影响,且状态一旦改变,就不会再变化。
可能的状态:
pending
进行中fulfilled
已成功rejected
已失败
状态改变:
pending
-->fulfilled
pending
-->rejected
状态一旦发生改变就会定型,称为resolved。如果改变已经发生,再对Promise
对象添加回调函数,也会立即得到这个结果。
Promise
创建后无法取消,pending
状态下也无法得知进度。
创建Promise
实例:
const promise = new Promise(function(resolve, reject){
.....
if (/*操作成功*/) {
resolve(value);
} else {
reject(error);
}
});
其中,Promise
参数为一个函数,函数的两个参数分别是JS提供的resolve
和reject
函数;
resolve
函数将Promise
状态变为resolved;在异步操作成功时调用,并将异步操作的结果作为参数传递出去;
reject
函数将Promise
状态变为rejected;在操作失败时调用,并将操作失败报出的错误,作为参数传递出去。
设置这两个函数的回调函数
promise.then(function (value){
// 成功回调
}, function (error) {
// 失败回调
});
一个Ajax实例
const getJson = function (url) {
const promise = new Promise(function(resolve, reject){
const handler = function () {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.responseText);
} else {
reject(new Error(this.statusText));
}
}
const XHR = new XMLHttpRequest();
XHR.open("GET", url, true);
XHR.responseType = "json";
XHR.onreadystatechange = handler;
XHR.setRequestHeader("Accept", "application/json");
XHR.send()
});
return promise;
}
getJson("posts.json").then(function(json){
console.log("Contents: "+json);
}, function (error) {
console.error("Error: ", error);
});
Promise.prototype.then()
为Promise
实例添加状态改变时的回调函数,返回一个新的Promise
对象,可以采用链式写法,指定一组按照次序调用的回调函数;
注意then()
方法必须接收一个函数作为参数,否则then()
方法就会被视为then(null)
,不会起作用.
// 以下输出为1
Promise.resolve("1").then(Promise.resolve("2")).then(Promise.resolve("3"))
.then(function (value) {
console.log(value);
});
Promise.prototype.catch()
`then(null, rejection)的别名。用于指定发生错误时的回调函数;
Promise对象的错误具有冒泡性质,出现错误后会不停向后传递直到被捕获为止;但如果没有用catch
方法指定回调函数,Promise对象内部的错误不会传递到外部;
一般建议Promise对象后面要跟catch
方法,这样可以处理Promise对象内部的错误;该方法返回的还是一个Promise对象。
建议在then
方法中定义resolve
方法,而在catch
方法中定义Reject状态的回调函数。
promise.then(function (value) {
//resolve函数
}).catch(function (error) {
//reject函数
});
Promise.prototype.finally()
添加不论Promise对象最终的状态是Resolved还是Rejected都会执行的函数;
Promise.all()
用于把多个Promise实例,包装成一个新的Promise实例。参数必须是有Iterator接口的结构,且返回的成员都为Promise实例。对于数组参数,如果有不是Promise对象的项,会先调用promise.resolve()
方法将其转为Promise对象。
参数中所有的Promise对象的状态是逻辑与的关系,只有都变成了fulfilled
,总的Promise对象的状态才会变成fulfilled
,所有返回值组成数组传给总对象的回调函数;
而只要有一个是rejected
,总的Promise对象也会变为rejected
,第一个被reject
的实例的返回值被传给总对象的回调函数。
Promise.race()
同样是将多个Promise对象包装成一个Promise对象,但是参数对象只要有一个状态发生改变,总函数对象就会跟着改变,并把这个参数对象的返回值传递给总对象的回调函数;
Promise.resolve()
参数情况:
- Promise实例--该方法直接返回该实例;
- 不是Promise实例,但具有
then
方法--把该对象变成Promise实例,并立即执行其then
方法; - 不是具有
then
方法的对象--返回一个新的Promise对象,状态为resolved
,参数会传给回调函数; - 没有参数--直接返回一个
resolved
状态的Promise对象;
关于执行时机:
立即resolve
的Promise对象是在本轮“事件循环”结束时,而不是下一轮“事件循环”开始时;(setTimeout()
的回调函数是下一轮“事件循环”开始时)。
setTimeout(function () {console.log("setTimeout out1")}, 0);
Promise.resolve().then(function () {
console.log("Promise out1");
});
console.log("direct 1");
setTimeout(function () {console.log("setTimeout out2")}, 0);
Promise.resolve().then(function () {
console.log("Promise out2");
});
console.log("direct 2");
// direct out1
// direct out2
// Promise out1
// Promise out2
// setTimeout out1
// setTimeout out2
Promise.reject()
该方法返回一个状态为rejected
的Promise对象,并把参数直接传递给回调函数,立即执行。
Promise.try()
模拟try
代码块,可以捕捉同步或异步的错误:
Promise.try(function () {
......
}).then(function (value) {
......
}).catch(function (error) {
......
})
Promise的深入理解
参考:We have a problem with promises
-
Promise对象的
then()
方法会返回一个新的Promise对象,then()
方法的参数如果不是函数,会直接被视为then(null)
对待; -
作为
.then()
方法的参数的函数中,如果没有使用return
返回某些值,将不会把结果输出到下一个方法中(undefined
),该方法变成同步方法,下一个then
中的回调函数将不会等待这个函数执行结束;建议始终在then()
方法的参数中始终使用return
或throw
; -
可能返回的合理的值包括:
- 一个新的Promise对象;
- 一个同步的值;
- 抛出一个同步的错误;
-
使用
Promise.resolve()
和Promise.reject()
, 可以方便地返回一个立即resolved
或rejected
的Promise对象,用其封装一些同步方法可以很好地管理then()
和捕捉错误;
function somePromiseAPI() {
return Promise.resolve().then(function () {
doSomeThingThatMayThrow();
return "foo";
}).then(/*.......*/);
}
then(resolve, reject)
中的reject
回调函数只捕捉调用then()
的Promise对象内的错误,而不会捕捉resolve
函数中的错误;而.then(resolve, reject).catch(function (erroe)...)
可以捕捉Promise对象和回调函数中的错误;
2018-5-26