Promise
是 JS 中处理异步的一种方式,传统方式通过 callbacks
,但是会有回调地狱问题,可读性极差。
Promise
仍然存在链式调用的问题,然后出现了 async
await
语法糖,这两个语法糖通过 Promise
+Generator
实现。
Promise A+ 规范
Promise 在整个生命周期中有且仅有三种状态,一旦状态变为 Fulfilled
或 Rejected
,Promise 的状态将变为不可变
。
Pending
(进行中):Promise 初始状态,可以转变为 Fulfilled 或 Rejected。Fulfilled
(已成功):Promise 完成状态,表示操作成功完成,并有一个值。完成状态不可更改。Rejected
(已失败):Promise 拒绝状态,表示操作失败,并有一个拒绝原因。拒绝状态不可更改。
手写一个简单的 Promise
const PENDING = "pending"
const RESOLVED = "resolved"
const REJECTED = "rejected"
class MyPromise {
constructor(executor) {
this.status = PEDING
this.value = null
this.reason = null
const resolve = (value) => {
this.status = RESOLVED
this.value = value
}
const reject = (reason) => {
this.status = REJECTED
this.reason = reason
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
考虑异步情况,then时判断如果状态仍为 PENDING 则追加到回调列表,不能确保1秒后才执行then函数,但是可以保证1秒后再执行then里的回调。
const PENDING = "pending"
const RESOLVED = "resolved"
const REJECTED = "rejected"
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = null
this.reason = null
this.fulfilledCallbacks = [] // 存储then成功的回调
this.rejectedCallbacks = [] // 存储then失败的回调
const resolve = (value) => {
if (this.status === PENDING) {
this.value = value
this.status = RESOLVED
this.fulfilledCallbacks.forEach((cb) => cb(value))
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
this.rejectedCallbacks.forEach((cb) => cb(reason))
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
if (this.status === RESOLVED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else if (this.status === PENDING) {
this.fulfilledCallbacks.push(() => {
onFulfilled(this.value)
})
this.rejectedCallbacks.push((reason) => {
onRejected(reason)
})
}
}
catch(onRejected) {
if (this.status === REJECTED) {
onRejected(this.reason)
} else if (this.status === PENDING) {
this.rejectedCallbacks.push((reason) => {
onRejected(reason)
})
}
}
}
MyPromise.all = function (promises) {
return new MyPromise((resolve, reject) => {
let count = 0
const result = []
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(value) => {
count++
result[i] = value
if (count === promises.length) {
resolve(result)
}
},
(reason) => {
reject(reason)
}
)
}
})
}
MyPromise.race = function (promises) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(value) => {
resolve(value)
},
(reason) => {
reject(reason)
}
)
}
})
}
测试
// 测试同步resolve
const promise1 = new MyPromise((resolve) => {
resolve("同步成功")
})
promise1.then(
(value) => console.log("同步测试1:", value), // 期望输出: "同步测试1: 同步成功"
(reason) => console.log("同步测试1失败:", reason)
)
// 测试同步reject
const promise2 = new MyPromise((_, reject) => {
reject("同步失败")
})
promise2.then(
(value) => console.log("同步测试2:", value),
(reason) => console.log("同步测试2失败:", reason) // 期望输出: "同步测试2失败: 同步失败"
)
// 测试异步resolve
const promise3 = new MyPromise((resolve) => {
setTimeout(() => resolve("异步成功"), 100)
})
promise3.then(
(value) => console.log("异步测试1:", value), // 期望输出: "异步测试1: 异步成功"
(reason) => console.log("异步测试1失败:", reason)
)
// 测试异步reject
const promise4 = new MyPromise((_, reject) => {
setTimeout(() => reject("异步失败"), 100)
})
promise4.then(
(value) => console.log("异步测试2:", value),
(reason) => console.log("异步测试2失败:", reason) // 期望输出: "异步测试2失败: 异步失败"
)
// 测试 catch 异步错误
const promise5 = new MyPromise((_, reject) => {
setTimeout(() => reject("catch测试异步失败"), 100)
})
promise5.catch((reason) => console.log("catch测试:", reason)) // 期望输出: "catch测试: catch测试异步失败"
// 测试 MyPromise.all,全部成功
const promise6 = new MyPromise((resolve) => resolve("结果1"))
const promise7 = new MyPromise((resolve) => resolve("结果2"))
MyPromise.all([promise6, promise7]).then(
(values) => console.log("Promise.all成功:", values), // 期望输出: "Promise.all成功: [ '结果1', '结果2' ]"
(reason) => console.log("Promise.all失败:", reason)
)
// 测试 MyPromise.all,部分失败
const promise8 = new MyPromise((resolve) => resolve("结果1"))
const promise9 = new MyPromise((_, reject) => reject("失败原因"))
MyPromise.all([promise8, promise9]).then(
(values) => console.log("Promise.all成功:", values),
(reason) => console.log("Promise.all失败:", reason) // 期望输出: "Promise.all失败: 失败原因"
)
// 测试 MyPromise.race,返回最先完成的结果
const promise10 = new MyPromise((resolve) =>
setTimeout(() => resolve("最先完成"), 50)
)
const promise11 = new MyPromise((resolve) =>
setTimeout(() => resolve("较晚完成"), 100)
)
MyPromise.race([promise10, promise11]).then(
(value) => console.log("Promise.race成功:", value), // 期望输出: "Promise.race成功: 最先完成"
(reason) => console.log("Promise.race失败:", reason)
)
// 测试 MyPromise.race,返回最先失败的结果
const promise12 = new MyPromise((_, reject) =>
setTimeout(() => reject("最先失败"), 50)
)
const promise13 = new MyPromise((resolve) =>
setTimeout(() => resolve("成功结果"), 100)
)
MyPromise.race([promise12, promise13]).then(
(value) => console.log("Promise.race成功:", value),
(reason) => console.log("Promise.race失败:", reason) // 期望输出: "Promise.race失败: 最先失败"
)