基础
ES6原生提供了Promise对象,用来保存某个异步操作的结果。其状态不受外界影响,且状态一旦改变,就不会再变化。
可能的状态:
pending进行中fulfilled已成功rejected已失败
状态改变:
pending-->fulfilledpending-->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
posted on
浙公网安备 33010602011771号