JavaScript的Promise
1. Promise的概述
Promise
对象表示异步操作最终的完成(或失败)以及其结果值。
Promise
允许将处理程序与异步操作的最终成功值或失败原因关联起来,使得异步方法可以像同步方法一样返回值。
1.1 Promise的三种状态
Promise
有三种状态,一旦状态从初始状态变成其他状态,就不会再改变。
- 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled):操作成功。
- 已拒绝(rejected):操作失败。
1.2 Promise的实例方法
- then():
Promise
被兑现时调用。 - catch():
Promise
被拒绝时调用。 - finally():无论
Promise
是否被兑现还是被拒绝,处理器都会在Promise
敲定时被调用。
1.3 Promise的基本使用
Promise
的构造函数有两个参数。
- resolve:被兑现时调用resolve函数
- reject:被拒绝时调用reject函数
// 创建一个Promise对象
let promise = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
}, 1000);
} );
// 状态从 pending -> fulfilled 执行 then
// 状态从 pending -> rejected 执行 catch
// finally 总是会执行
promise.then(data => {
console.log(data)
}).catch(err => {
console.log(err)
}).finally(() => {
console.log("finally")
});
2. Promise 链式调用
.then()
最多接受两个参数,第一个参数是 Promise
兑现时的回调函数,第二个参数是 Promise
拒绝时的回调函数。每个 .then()
返回一个新生成的 Promise
对象,这个对象可被用于链式调用。
// 创建一个Promise对象
let promise = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
}, 1000);
} );
// 兑现的回调函数
function handleFulfilledA(data) {
console.log(data);
return new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
}, 1000);
} );
}
// 拒绝的回调函数
function handleRejectedA(err) {
console.log(err);
return new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
}, 1000);
} );
}
// 兑现的回调函数
function handleFulfilledB(data) {
console.log(data);
}
// 拒绝的回调函数
function handleRejectedB(err) {
console.log(err);
}
promise
.then(handleFulfilledA, handleRejectedA)
.then(handleFulfilledB, handleRejectedB)
.finally(() => {
console.log("finally")
})
即使 .then()
缺少返回 Promise
对象的回调函数,处理程序仍会继续到链的下一个链式调用。
// 创建一个Promise对象
let promise = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
}, 1000);
} );
promise
.then((data) => {console.log(data); return data})
.then((data) => {console.log(data); return data})
.then((data) => console.log(data))
.catch((err) => console.log(err))
3. Promise 并发
Promise
类提供了四个静态方法来促进异步任务的并发。
3.1 all方法
all()
方法在所有传入的 Promise
都被兑现时兑现;在任意一个 Promise
被拒绝时拒绝。
let promise1 = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
}, 1000);
} );
let promise2 = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
}, 1000);
} );
// promise1 和 promise2 都从 pending -> fulfilled 走 then,接收到一个数组,装着所有 Promise 的返回
// promise1 和 promise2 其中一个从 pending -> rejected 走 catch
Promise
.all([promise1, promise2])
.then((data) => {
console.log(data);
}).catch((err) => {
console.log(err);
})
3.2 race 用法
race()
方法只要有一个异步执行完成,不管是兑现还是拒绝就执行回调,其余的都不再执行回调。
let promise1 = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
},1000 );
} );
let promise2 = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
},1000 );
} );
Promise
.race([promise1, promise2])
.then((data) => console.log(data))
.catch((err) => console.log(err))
3.3 allSettled 用法
allSettled()
方法需要所有异步执行结束,返回一个数组,装着所有 Promise
的执行结果。
let promise1 = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
},1000 );
} );
let promise2 = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
// num > 10 时走兑现逻辑,num <= 10 时走拒绝逻辑
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
},1000 );
} );
Promise
.allSettled([promise1, promise2])
.then((data) => {
let success = data.filter((item) => item.status === "fulfilled");
let fail = data.filter((item) => item.status === "rejected");
console.log(success);
console.log(fail);
});
3.4 any 用法
any()
方法只要有一个异步成功,就走 then;否则走 catch。
let promise1 = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
},1000 );
} );
let promise2 = new Promise( (resolve, reject) => {
// 进行异步操作
setTimeout( () => {
let num = Math.ceil(Math.random() * 20);
if (num > 10) {
resolve(`${num} > 10,执行成功!`);
} else {
reject(`${num} <= 10,执行失败!`);
}
},1000 );
} );
Promise
.any([promise1, promise2])
.then((data) => {
console.log(data);
}).catch((err) => {
// AggregateError对象,对象包含一个errors属性,值是数组类型,装着Promise的返回
console.log(err.errors);
});