什么是promise?
异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大,ES6 将其写进了语言标准
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件,通过统一api进行操作。
两个特点
(1)对象的状态不受外界影响:pending(进行中)、fulfilled(已成功)和rejected(已失败)这几种状态,外界是无法干预的
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果:如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果
优点:
1.避免了层层嵌套的回调函数
2.优于事件,事件错过就监听不到,Promise还是会返回当前确定的结果
3.统一api,流程清楚
缺点:
1.无法取消Promise,一旦新建它就会立即执行,无法中途取消
2.如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
3.当处于pending状态时,无法得知目前进展到哪一个阶段
基本用法
// 创建一个
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
//使用
promise.then(function(value) {
// success
}, function(error) {
// failure
});
一个例子:
下面是异步加载图片的例子。
function loadImageAsync(url) {
return new Promise(function(resolve, reject) {
const image = new Image();
image.onload = function() {
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
};
image.src = url;
});
}下面是一个用Promise对象实现的 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.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});这个用法已经能满足90%的需求了。。。。。。
进阶篇
常用api
Promise.all()
用于需要多个请求都执行完成在操作的场景,并发执行多个请求
全成功才是成功(p1, p2, p3必须是promise对象)
const p = Promise.all([p1, p2, p3]);Promise.race()
有一个成功就是成功(p1, p2, p3必须是promise对象)
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
Promise.allSettled()
同上面的两个
Promise.allSettled()方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束
Promise.any()
Promise.any()方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。该方法
all() race() allSettled() any() 总结
相同点:
1.这四个方法都是接受一组 Promise 实例(ps:可以不是,这个先不讲)作为参数,包装成一个新的 Promise 实例
2.并发执行
不同点:
all()
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数(应该是catch)(ps:如果 p1、p2、p3自身有.catch(e => e); 那么久不会执行 p 的catch,而是执行p的then方法)
race()
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。(示例:如果 5 秒之内fetch方法无法返回结果)
allSettled()
等到三个请求都结束,不管请求成功还是失败,最后的状态总是fulfilled
any()
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态
Promise.prototype.then()
基础的用法,不解释
Promise.prototype.finally()
无论如何都会执行的函数
异常处理
Promise.prototype.catch()
要点总结:上一个错误总是会被下一个catch捕获,总是使用catch,Promise内部错误即使没有捕获也不会终止程序()
Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数
1Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
2一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
3跟传统的try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。不会退出进程、终止脚本执行,通俗的说法就是“Promise 会吃掉错误”。
4代码运行完catch方法指定的回调函数,会接着运行后面那个then方法指定的回调函数。如果没有报错,则会跳过catch方法