1、概念
Promise 是 JavaScript 中用于异步编程的一种对象,解决了回调地狱的问题。
一个 Promise 有三种状态:
- Pending(等待):初始状态,既不是成功,也不是失败状态。
- Fulfilled(已成功):意味着操作成功完成。
- Rejected(已失败):意味着操作失败。
Promise是一个构造函数,接受一个函数作为参数,该函数的两个参数分别是resolve和reject,它们是两个函数。
resolve函数的作用是,将Promise对象的状态从“等待”变为“成功”(即从 pending 变为 fulfilled)
reject函数的作用是,将Promise对象的状态从“等待”变为“失败”(即从 pending 变为 rejected)
Promise 的一个常见用途是处理异步操作,比如网络请求、文件读写等。使用 Promise 可以避免回调地狱(callback hell),让代码更加清晰和易于维护。
2、Promise的实例方法
Promise的实例有 .then()
, .catch()
, 和 .finally()
这些方法来处理异步操作的结果。
- .then():当 Promise 状态变为 Fulfilled 时,会调用这个方法。then函数接收两个参数,一个onResolved(Promise 的状态为成功时候调用),一个onRejected(Promise 的状态为失败时候调用)。
- .catch():当 Promise 状态变为 Rejected 时,会调用这个方法。它接受一个函数作为参数,这个函数会在 Promise 失败时执行。(catch方法实际就是then方法只传onRejected时的语法糖)
- .finally():无论 Promise 的状态是 Fulfilled 还是 Rejected,都会调用这个方法。它接受一个函数作为参数,这个函数会在 Promise 完成后执行,无论成功还是失败。
3、Promise的静态方法
-
Promise.all() // 并发处理多个异步任务,所有任务都执行成功才能得到结果
-
Promise.race() // 并发处理多个异步任务,只要有一个任务执行完就得到结果
-
Promise.any() // 并发处理多个异步任务,只要有一个任务执行成功就得到结果
-
Promise.resolve() // 将现有对象转为fulfilled状态的 Promise对象
-
Promise.reject() // 将现有对象转为rejected状态的 Promise对象
4、手写一个函数实现Promise
//立使用立即执行函数,实现闭包
var MyPromise = (function(window){
// 三个状态会多次使用时,所以不建议写死
const PENDING = 'pending'; // 等待
const RESOLVED = 'resolved'; // 成功
const REJECTED ='rejected'; // 失败
// 返回一个class,可以实例化
return class MyPromise {
// 构造函数,参数是一个回调函数
constructor(fn){
this.status = PENDING; // 初始状态为等待
this.value = undefined; // 成功状态的数据
this.reason = undefined; // 失败状态的数据
// 异步操作
this.onFulfilledCallbacks = []; // 成功的回调函数数组
this.onRejectedCallbacks = []; // 失败的回调函数数组
// 声明成功的方法
const resolve = value => {
// 只有状态为等待时才能修改状态
if(this.status == PENDING){
this.status = RESOLVED // 修改状态为成功
this.value = value // 保存成功状态的数据
// 状态为成功时,执行成功的回调函数
this.onFulfilledCallbacks.forEach(cb => cb())
}
}
// 声明失败的方法
const reject = value => {
// 只有状态为等待时才能修改状态
if(this.status == PENDING){
this.status = REJECTED // 修改状态为失败
this.reason = value // 保存失败状态的数据
// 状态为失败时,执行失败的回调函数
this.onRejectedCallbacks.map(cb => cb())
}
}
// 同步代码的错误处理,要使用try...catch
try{
fn(resolve, reject) // 调用构造函数的参数并传入两个方法
} catch(error){
reject(error) // 出现错误就直接把状态修改为失败
}
}
// then方法,接收两个参数,分别是成功和失败的回调函数
then(onFulfilled, onRejected){
// 如果状态为成功执行参数1的回调函数
if(this.status === RESOLVED){
onFulfilled && onFulfilled(this.value)
}
// 如果状态为失败执行参数2的回调函数
if(this.status === REJECTED){
onRejected && onRejected(this.reason) // &&是为了避免onRejected为undefined的情况
}
// 如果状态为等待,则将回调函数保存到对应的数组中
if(this.status == PENDING){
this.onFulfilledCallbacks.push(()=>{
onFulfilled && onFulfilled(this.value)
})
this.onRejectedCallbacks.push(()=>{
onRejected && onRejected(this.reason)
})
}
return this // 返回this,可以链式调用
}
// catch方法,接收一个参数,是失败的回调函数
catch(onRejected){
this.then(null,onRejected) //失败就直接调用写好的then方法
return this // 返回this,可以链式调用
}
// finally方法,无论成功还是失败都会执行
finally(cb){
return this.then(() => cb(), () => cb()) //
}
}
})(window)
使用该函数,为了模拟异步操作,使用延时器:
// 使用
new MyPromise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve('new Promise 成功')
} else {
reject('new Promise 失败')
}
},1000)
})
.then(res => {
console.log('then方法参数1:', res);
}, err => {
console.log('then方法参数2:', err);
})
.catch(err => {
console.log('catch方法:', err);
})
.finally(() => {
console.log('finally方法');
})
当Math.random()随机数大于0.5时结果为成功,控制台显示如下:
当Math.random()随机数小于0.5时结果为失败,控制台显示如下: