MDN上面对promise的解释:
Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象
我的理解就是:Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大。
基本写法
let pro = new Promise((res, rej) => {
res(1);
rej(2);
});
pro.then(
data => console.log(data),
err => console.log(err)
);
在ES6中,将一件可以发生异步操作的事件,分为两个阶段unsettled
未决阶段和settled
已决阶段
在上述代码中,通过new 生成promise对象的时候的promise函数内为未决阶段,在通过then方法处理异步操作的时候为已决阶段。
ES6也将程序分为三种状态pendding resolved rejected
pendding状态处于unsettled
未决阶段,resolved rejected状态都处于settled
已决阶段。
上述代码中通过new 生成promise对象的时候的promise函数内为padding状态,函数内res把程序推向resolved状态,函数内rej把程序推向rejected状态。
在promise中,一次只能把程序推向一种状态,也就是res或者rej只能执行一个,上述代码用于演示所以同时写了两个。
pro.then方法用于接收promise内推出的状态,参数为两个函数,第一个函数接收res推出的resolved状态,第二个参数接收rej推出的rejected状态。
promise内抛出错误也会把padding状态推向rejected状态。
在unsettled
阶段,所有的代码都是同步执行,当处于settled
阶段就是异步了。也就是res或者rej推向的结果会异步执行。
多种情况下展示promise的异步操作
setTimeout(function(){
console.log(3);
},0)
let pro = new Promise((res, rej) => {
res(1);
console.log(2);
});
pro.then(
data => console.log(data),
err => console.log(err)
);
console.log(4);
结果会一次输出2 4 1 3。
定时器是异步操作,所以不会一开始就输出。在生成promise的函数内也就是处于unsettled
未决阶段是同步操作。但是res是异步操作,所以最先输出 2 。接着由于res是异步操作所以继续往下执行碰到输出4。然后剩下两个异步操作,在js中异步操作会被放入队列中等待执行,队列又分为微队列和宏队列,微队列先于宏队列里的事件加入执行栈。定时器是方法宏队列中,promise的处理是放在微队列中,所以先输出1,在输出3。最终就是 2 4 1 3。
then
promsie中的then方法可以是链式调用。链式链式调用时,如果前一个promise返回的是一个promise,则下一个返回的promise状态和后续处理返回的promise状态一致。
let pro1 = new Promise((res, rej) => {
res(1);
});
let pro2 = new Promise((res, rej) => {
rej(2);
});
let pro3 = pro1.then(data => pro1, err => pro2); // pro3.then 输出1
// let pro3 = pro2.then(data => pro1, err => pro2); // pro3.then 输出2
pro3.then(
data => console.log(data),
err => console.log(err)
);
promise中的API
catch
catch等同于then方法,但是只接收rej传入的rejected状态。
let pro1 = new Promise((res, rej) => {
res(1);
})
let pro2 = new Promise((res, rej) => {
rej(2);
});
pro1.catch(err => console.log(err)); // 报错 Uncaught (in promise) 2
pro2.catch(err => console.log(err)); // 2
resolve()
直接把promise推向resolved状态
let pro1 = new Promise((res, rej) => {
res(1);
});
// resolve简写
let pro1 = Promise.resolve(1);
reject()
直接把promise推向rejected状态
let pro1 = new Promise((res, rej) => {
rej(1);
});
// 等同于
let pro1 = Promise.reject(1);
all(arr)
这个方法返回一个新的promise,传入一个promise数组,所有的promise对象都推向resolve就推向成功,一旦有一个失败该promise对象推向失败。
// 模拟
let arr = [];
for(let i = 0; i < 10; i++){ // 模拟成功失败随机
arr.push(new Promise((res, rej) => {
if(Math.random() > 0.8){
res(1);
} else {
rej(Math.floor(Math.random() * 10));
}
}));
}
// for(let i = 0; i < 10; i++){ // 模拟全部成功
// arr.push(Promise.resolve(1));
// }
console.log(arr);
let pro = Promise.all(arr);
pro.then(data => {console.log(data)});
pro.catch(err => {console.log(err)});
总结:如果全部成功,则输出每一个promise的resolve结果,如果有一个失败,则直接输出第一个失败的结果。
rach(arr)
当数组中任意一个promise对象完成时,就马上会去使用完成了的promise对象的结果,不管这个结果是成功还是失败
let arr = [];
let pro1 = new Promise((res, rej) => {
setTimeout(() => {
res("pro1");
}, 1000);
});
let pro2 = new Promise((res, rej) => {
setTimeout(() => {
rej("pro2");
}, 500);
});
arr.push(pro1, pro2);
console.log(arr);
let pro = Promise.race(arr);
pro.then(data => {console.log(data)});
pro.catch(err => {console.log(err)});
总结:输出pro2, pro2推向已决状态用时少,所以先执行pro2。