promise
是一种异步编程的解决方案,通过链式调用解决回调地狱的问题
有三种状态:pending,fulfilled 和rejected,状态一旦发生改变就不会再变
1. 基本用法
// promise 是一个构造函数,接收一个函数作为参数,函数的两个参数又为函数分别为resolve (成功时调用)和reject(失败时调用)
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise.prototype.then()
//可以指定一组按照次序调用的回调函数
promise.then(function(value) {
// success
}, function(error) {
// failure
});
Promise.prototype.catch()
指定发生错误时的回调函数,,promise抛出一个错误,就被catch()方法指定的回调函数捕获。
/ 写法一
const promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
promise.catch(function(error) {
console.log(error);
});
// 写法二
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
// Promise 在resolve语句后面,再抛出错误,不会被捕获,等于没有抛出。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了。
一般不要在then()方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。第二种写法可以捕获前面then方法执行中的错误,也更接近同步的写法(try/catch)。因此,建议总是使用catch()方法,而不使用then()方法的第二个参数。catch()方法返回的还是一个 Promise 对象,因此后面还可以接着调用then()方法。
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
Promise.prototype.finally()
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。finally方法总是会返回原来的值。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
Promise.all()
Promise.all()方法接受一个数组作为参数
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]
/**
* p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。
*/
const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 延时一秒')
}, 1000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3 延时两秒')
}, 2000)
})
const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('p5 rejected 延时1.5秒')
}, 1500)
})
// 所有Promise实例都成功
Promise.all([p1, p2, p3])
.then(res => {
console.log(res)
})
.catch(err => console.log(err)) // 2秒后打印 [ 'p1', 'p2 延时一秒', 'p3 延时两秒' ]
// 一个Promise实例失败
Promise.all([p1, p2, p4])
.then(res => {
console.log(res)
})
.catch(err => console.log(err)) // p4 rejected
// 一个延时失败的Promise
Promise.all([p1, p2, p5])
.then(res => {
console.log(res)
})
.catch(err => console.log(err)) // 1.5秒后打印 p5 rejected
// 两个Promise实例失败
Promise.all([p1, p4, p5])
.then(res => {
console.log(res)
})
.catch(err => console.log(err)) // p4 rejected
Promise.race()
接受一个数组作为参数
const p = Promise.race([p1, p2, p3]);
// ,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 延时一秒')
}, 1000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3 延时两秒')
}, 2000)
})
const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('p5 rejected 延时1秒')
}, 1500)
})
// p1无延时,p2延时1s,p3延时2s
Promise.race([p1, p2, p3])
.then(res => console.log(res))
.catch(err => console.log(err)) // p1
// p4无延时reject
Promise.race([p4, p2, p3])
.then(res => console.log(res))
.catch(err => console.log(err)) // p4 rejected
// p5 延时1.5秒reject,p2延时1s
Promise.race([p5, p2, p3])
.then(res => console.log(res))
.catch(err => console.log(err)) // 1s后打印: p2 延时一秒
Promise.allSettled()
方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的 Promise 对象才会发生状态变更。不管一组 Promise 实例的各自结果如何,Promise.allSettled 都会转变为 fulfilled 状态。
const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 延时一秒')
}, 1000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3 延时两秒')
}, 2000)
})
const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('p5 rejected 延时1.5秒')
}, 1500)
})
// 所有 Promise 实例都成功
Promise.allSettled([p1, p2, p3])
.then(res => console.log(res))
.catch(err => console.log(err))
// [
// { status: 'fulfilled', value: 'p1' },
// { status: 'fulfilled', value: 'p2 延时一秒' },
// { status: 'fulfilled', value: 'p3 延时两秒' }
// ]
// 有一个 Promise 失败
Promise.allSettled([p1, p2, p4])
.then(res => console.log(res))
.catch(err => console.log(err))
// [
// { status: 'fulfilled', value: 'p1' },
// { status: 'fulfilled', value: 'p2 延时一秒' },
// { status: 'rejected' , value: 'p4 rejected' }
// ]
// 所有 Promise 都失败
Promise.allSettled([p4, p5])
.then(res => console.log(res))
.catch(err => console.log(err))
// [
// { status: 'rejected', reason: 'p4 rejected' },
// { status: 'rejected', reason: 'p5 rejected 延时1.5秒' }
// ]
Promise.any()
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
// 所有 Promise 都成功
Promise.MyAny([p1, p2, p3])
.then(res => console.log(res))
.catch(err => console.log(err)) // p1
// 两个 Promise 成功
Promise.MyAny([p1, p2, p4])
.then(res => console.log(res))
.catch(err => console.log(err)) // p1
// 只有一个延时成功的 Promise
Promise.MyAny([p2, p4, p5])
.then(res => console.log(res))
.catch(err => console.log(err)) // p2 延时1秒
// 所有 Promise 都失败
Promise.MyAny([p4, p5])
.then(res => console.log(res))
.catch(err => console.log(err)) // 没有promise成功