手写 Promise
需要实现的功能
-
初始化 & 异步调用
// Promise 的参数是个函数,函数里有两个参数,一个是成功回调,一个是失败回调 const p1 = new Promise((resolve, reject) => { resolve(100) // 也支持异步 // setTimeout(() => { // resolve(100) // }, 500) })
-
then、catch 链式调用
p.then((data) => { return data + 1 }).then((data) => { return data + 2 }).catch((err) => { console.log(err) }) // then 也可以传入两个参数 // 一个是成功后的回调,一个是失败后的回调 p.then(fn1, fn2) // 链式调用本质是每次调用返回一个新的 promise const p11 = p1.then((data) => { return data + 1 }) const p12 = p11.then((data) => { return data + 2 }) const p13 = p12.catch((err) => { console.log(err) })
-
API .resolve .reject .all .race
// 创建一个 resolved 状态的 promise 并附带成功信息 const p2 = Promise.resolve(200) // 创建一个 rejected 状态的 promise,并附带 rejected 的原因 const p3 = Promise.reject("错误信息...") // 当所有 promise 都 resolved 后返回数组结果。 // 如果有 rejected 则返回 rejected 状态的 promise 并说明错误原因 const p4 = Promise.all([p1, p2]) // 哪个 promise 先执行完就直接返回,不管是 resolved 或 rejected const p5 = Promise.race([p1, p2])
1. 构造函数
class MyPromise {
constructor (fn) {
this.state = 'pending' // 状态,'pending' 'resolved', 'rejected
this.value = undefined // 成功后的值
this.reason = undefined // 失败后的原因
this.resolveCallbacks = []; // pending 状态下,存储成功的回调
this.rejectCallbacks = []; // pending 状态下,存储失败的回调
const resolveHandler = (value) => {
if (this.state === 'pending') {
this.state = 'resolved'
this.value = value
// 状态变化后,执行存储的回调方法
this.resolveCallbacks.forEach(fn => fn(this.value))
}
}
const rejectHandler = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.rejectCallbacks.forEach(fn => fn(this.reason))
}
}
try {
fn(resolveHandler, rejectHandler)
} catch (err) {
rejectHandler(err)
}
}
then(fn1, fn2) {
// 当 pending 状态下,fn1 fn2 会被存储到 callback 中
}
// 就是 then 的一个语法糖,简单模式
catch(fn) {
return this.then(null, fn)
}
}
2. then 的链式调用
class MyPromise {
constructor (fn) {
this.state = 'pending' // 状态,'pending' 'resolved', 'rejected
this.value = undefined // 成功后的值
this.reason = undefined // 失败后的原因
this.resolveCallbacks = []; // pending 状态下,存储成功的回调
this.rejectCallbacks = []; // pending 状态下,存储失败的回调
const resolveHandler = (value) => {
if (this.state === 'pending') {
this.state = 'resolved'
this.value = value
this.resolveCallbacks.forEach(fn => fn(this.value))
}
}
const rejectHandler = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.resolveCallbacks.forEach(fn => fn(this.reason))
}
}
try {
fn(resolveHandler, rejectHandler)
} catch (error) {
rejectHandler(err)
}
}
then(fn1, fn2) {
// 当 pending 状态下,fn1 fn2 会被存储到 callback 中
fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
fn2 = typeof fn2 === 'function' ? fn2 : (v) => v
if (this.state === 'pending') {
return new MyPromise((resolve, reject) => {
// push 进去的函数得等状态为 resolved 的时候才会被执行
this.resolveCallbacks.push(() => {
try {
const newValue = fn1(this.value);
resolve(newValue)
} catch (err) {
reject(err)
}
})
// push 进去的函数得等状态为 rejected 的时候才会被执行
this.resolveCallbacks.push(() => {
try {
const newReason = fn2(this.reason);
reject(newReason )
} catch (err) {
reject(err)
}
})
})
}
// const p11 = p1.then((data) => {
// return data + 1
// })
if (this.state === 'resolved') {
return new MyPromise((resolve, reject) => {
try {
// 传入 resolved 的返回值
const newValue = fn1(this.value)
resolve(newValue)
} catch (error) {
reject(error)
}
})
}
if (this.state === 'rejected') {
return new MyPromise((resolve, reject) => {
try {
// 传入 rejected 的原因
const newReason = fn2(this.reason)
reject(newReason)
} catch (error) {
reject(error)
}
})
}
}
// 就是 then 的一个语法糖,简单模式
catch(fn) {
return this.then(null, fn)
}
}
3. Promise-all 和 race
class MyPromise {
constructor (fn) {
this.state = 'pending' // 状态,'pending' 'resolved', 'rejected
this.value = undefined // 成功后的值
this.reason = undefined // 失败后的原因
this.resolveCallbacks = []; // pending 状态下,存储成功的回调
this.rejectCallbacks = []; // pending 状态下,存储失败的回调
const resolveHandler = (value) => {
if (this.state === 'pending') {
this.state = 'resolved'
this.value = value
this.resolveCallbacks.forEach(fn => fn(this.value))
}
}
const rejectHandler = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.resolveCallbacks.forEach(fn => fn(this.reason))
}
}
try {
fn(resolveHandler, rejectHandler)
} catch (error) {
rejectHandler(error)
}
}
then(fn1, fn2) {
// 当 pending 状态下,fn1 fn2 会被存储到 callback 中
fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
fn2 = typeof fn2 === 'function' ? fn2 : (v) => v
if (this.state === 'pending') {
return new MyPromise((resolve, reject) => {
// push 进去的函数得等状态为 resolved 的时候才会被执行
this.resolveCallbacks.push(() => {
try {
const newValue = fn1(this.value);
resolve(newValue)
} catch (error) {
reject(error)
}
})
// push 进去的函数得等状态为 rejected 的时候才会被执行
this.resolveCallbacks.push(() => {
try {
const newReason = fn2(this.reason);
reject(newReason)
} catch (error) {
reject(error)
}
})
})
}
// const p11 = p1.then((data) => {
// return data + 1
// })
if (this.state === 'resolved') {
return new MyPromise((resolve, reject) => {
try {
// 传入 resolved 的返回值
const newValue = fn1(this.value)
resolve(newValue)
} catch (error) {
reject(error)
}
})
}
if (this.state === 'rejected') {
return new MyPromise((resolve, reject) => {
try {
// 传入 rejected 的原因
const newReason = fn2(this.reason)
reject(newReason)
} catch (error) {
reject(error)
}
})
}
}
// 就是 then 的一个语法糖,简单模式
catch(fn) {
return this.then(null, fn)
}
}
// 全局静态 API
MyPromise.resolve = function(value) {
return new MyPromise((resolve, reject) => resolve(value))
}
MyPromise.reject = function(reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
MyPromise.all = function (promiseList = []) {
const p1 = new MyPromise((resolve, reject) => {
const result = [] // 存储 promiseList 所有的结果
const length = promiseList.length
let resolvedCount = 0
promiseList.forEach((p) => {
p.then(data => {
result.push(data)
// resolvedCount 必须在 then 里面做 ++ (then 执行,累加才算数)
// 不能用 index,因为 promise 里是异步的,index 递增是同步的
resolvedCount++
if (resolvedCount === length) {
// 已经遍历到了最后一个 promise,把数据 resolve 出去
resolve(result)
}
}).catch(err => {
reject(err)
})
})
})
return p1
}
MyPromise.race = function (promiseList = []) {
let resolved = false
const p1 = new MyPromise((resolve, reject) => {
promiseList.forEach(p => {
p.then(data => {
if (!resolved) {
resolve(data)
resolved = true
}
}).catch((err) => {
reject(err)
})
})
})
return p1
}