Promise是异步编程的一种解决方案;
简单来说就是一个容器,里边保存着某个未来才会结束的事件的结果(通常是一个异步操作的结果)。
1.Promise对象有2个特点:
(1)对象的状态不受外界影响。
Promise对象代表一个异步操作,有3种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。
(2)只要状态改变,就不会再变,任何时候都可以得到这个结果
Promise对象状态改变有两种情况:从pending到fulfilled、从pending到rejected。
只要这两种情况发生,状态凝固不会再变,称为resolved(已定型)。
2.Promise的缺点:
(1)无法取消Promise。一旦新建就会立即执行,中途无法取消
(2)如果不设置回调函数,Promise内部抛出的错误,不会反映到外部
(3)当处于pending状态时,无法得知目前进行到哪个阶段
3.Promise基本用法
(1)Promise是一个构造函数 用来生成Promise实例
const promise = new Promise((resolve,reject) => {
// ...some code
if(/*异步操作成功*/){
resolve(value)
} else{
reject(error)
}
});
Promise构造函数接收一个函数作为参数。
resolve函数的作用是:在异步操作成功时调用;reject函数作用是在异步操作失败时调用
(2)Promise实例生成之后,可用then方法分别指定resolved和rejected状态的回调函数
promise.then((value) =>{
//success
},(error) => {
//failure
});
then方法可以接受两个回调函数作为参数,这两个函数都接受Promise对象传出去的值作为参数。第二个函数是可选的
(3)Promise对象例子: (Promise新建后会立即执行!!)
function timeout(ms){
return new Promise((resolve,reject) => {
console.log('promised'); //先输出这行代码
setTimeout(resolve,ms,'done');
});
}
timeout(100).then((vlaue) => {
console.log(value)
})
(4)用Promise写一个异步加载图片的例子:
function loadImageAsync(url){
return new Promise((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;
});
}
4.Promise.prototype.then()
Promise的then方法是定义在原型对象Promise.prototype上的,作用是为Promise实例添加状态改变时的回调函数
then方法返回的是一个新的Promise实例 可以采用链式方法,即then方法后再调一个then方法:
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
上边代码中,第一个回调函数完成以后,将结果作为参数传入第二个回调函数。
5.Promise.prototype.catch()
Promise.prototype.catch()方法是.then(null,rejection)或.then(undefined,rejection)的别名,用于指定发生错误时的回调函数
一般总是建议,Promise 对象后面要跟catch
方法,这样可以处理 Promise 内部发生的错误。
catch
方法返回的还是一个 Promise 对象,因此后面还可以接着调用then
方法
6.Promise.prototype.finally()
finally()方法用于指定不管Promise对象最后状态如何,都会执行的操作,该方法是ES2018引入标准的
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
finally()方法不接受任何参数,表明finally()里的操作不依赖于promise的执行结果
7.Promise.all()
Promise.all()方法用于将多个Promise实例包装成一个新的Promise实例
const p = Promise.all([p1,p2,p3]);
Promise.all()接受一个数组作为参数,p1,p2,p3都是Promise实例,如果不是,调用Promise.resolve()将参数转为Promise实例
p的状态由p1,p2,p3决定:
(1)只有三者状态都变成fulfilled,p的状态才会变成fulfilled,此时,三者的返回值组成一个数组传递给p的回调函数
(2)只要三者有一个被rejected,p的状态就会变成rejected,此时,第一个被rejected的实例的返回值传递给p的回调函数
8.Promise.race()
Promise.race()方法也是将多个Promise实例包装成一个新的Promise实例
const p = Promise.race([p1,p2,p3]);
和Promise.all不同的是:p1,p2,p3只要其中一个实例率先改变状态,p的状态就会跟着改变
9.Promise.allSettled()
Promise.allSettled()方法接收一组Promise实例作为参数,包装成一个新的Promise实例
只有等到这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束
const promises = [
fetch('/api-1'),
fetch('/api-2'),
fetch('/api-3')
];
await Promise.allSettled(promises);
removeLoadingIndicator();
该方法返回的新的Promise实例,一旦结束,状态总是fulfilled,不会变成rejected。
10.Promise.any()
Promise.any()
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例
只要参数实例有一个变成fulfilled,包装实例就会变成fulfilled;所有参数实例都变成rejected,包装实例会变成rejected。
11.Promise.resolve()
将现有对象转为Promise对象
const JSpromise = Promise.resolve($.ajax('/whatever.json'));
上面代码将 jQuery 生成的deferred
对象,转为一个新的 Promise 对象。
Promise.resolve()的参数有四种情况:
(1)参数是Promise实例,原封不动犯规这个实例
(2)参数是thenable对象(具有then方法的对象),则会将此对象转为Promise对象,然后立即执行thenable对象的then方法
(3)参数不是具有then方法的对象,或根本不是对象,则会返回一个新的Promise对象,状态为resolved
(4)不带任何参数,直接返回一个resolved状态的Promise对象
12.Promise.reject()
Promise.reject()方法返回一个新的Promise实例,状态为rejected
13.有关Promise对象的应用
加载图片:一旦加载完成,Promise的状态就会发生变化
const preloadImage = function (path) {
return new Promise(function (resolve, reject) {
const image = new Image();
image.onload = resolve;
image.onerror = reject;
image.src = path;
});
};
14.Promise.try()
不管函数f
是同步函数还是异步操作,可以 Promise 来处理它。
这样就可以不管f
是否包含异步操作,都用then
方法指定下一步流程,用catch
方法处理f
抛出的错误。
const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next