实现一个 promise
要从 0 实现一个 Promise/A+ 的所有功能,是非常复杂的。面试一共 1h ,不可能考这么详细。再者,绝大部分程序员也无法短时间、高质量的写出一个完整的 Promise 。因为日常不写,只用。
所以,面试考察“手写 Promise”考察的就是一个设计思路,编码能力。并不是真让你写出来使用。
Promise 基本功能(面试时能写出这些,就足够了)
- 初始化
- 异步执行
- thencatch 和 链式调用
.resolve.reject.all.race
写代码……
测试
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MyPromise</title>
</head>
<body>
<h1>MyPromise</h1>
<script src="./MyPromise.js"></script>
<script>
const p1 = new MyPromise((resolve, reject) => {
// resolve(100)
// reject('错误信息...')
setTimeout(() => {
resolve(100);
}, 1000);
});
// const p11 = p1.then(data1 => {
// console.log('data1', data1)
// return data1 + 1
// })
// const p12 = p11.then(data2 => {
// console.log('data2', data2)
// return data2 + 2
// })
// const p13 = p12.catch(err => console.error(err))
const p2 = MyPromise.resolve(200);
const p3 = MyPromise.resolve(300);
const p4 = MyPromise.reject("错误信息...");
// 传入 promise 数组,等待所有的都 fulfilled 之后,返回新 promise ,包含前面所有的结果
// const p5 = MyPromise.all([p1, p2, p3])
// p5.then(result => console.log('all result', result))
const p6 = MyPromise.race([p1, p2, p3]); // 传入 promise 数组,只要有一个 fulfilled 即可返回
p6.then((result) => console.log("race result", result));
</script>
</body>
</html>MyPromise.js
javascript
class MyPromise {
state = 'pending' // 状态,'pending' 'fulfilled' 'rejected'
value = undefined // 成功后的值
reason = undefined // 失败后的原因
resolveCallbacks = [] // pending 状态下,存储成功的回调
rejectCallbacks = [] // pending 状态下,存储失败的回调
constructor(fn) {
const resolveHandler = (value) => {
// 加 setTimeout ,参考 https://coding.imooc.com/learn/questiondetail/257287.html (2022.01.21)
setTimeout(() => {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.resolveCallbacks.forEach(fn => fn(value))
}
})
}
const rejectHandler = (reason) => {
// 加 setTimeout ,参考 https://coding.imooc.com/learn/questiondetail/257287.html (2022.01.21)
setTimeout(() => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.rejectCallbacks.forEach(fn => fn(reason))
}
})
}
try {
fn(resolveHandler, rejectHandler)
} catch (err) {
rejectHandler(err)
}
}
then(fn1, fn2) {
fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
fn2 = typeof fn2 === 'function' ? fn2 : (e) => e
if (this.state === 'pending') {
const p1 = new MyPromise((resolve, reject) => {
this.resolveCallbacks.push(() => {
try {
const newValue = fn1(this.value)
resolve(newValue)
} catch (err) {
reject(err)
}
})
this.rejectCallbacks.push(() => {
try {
const newReason = fn2(this.reason)
reject(newReason)
} catch (err) {
reject(err)
}
})
})
return p1
}
if (this.state === 'fulfilled') {
const p1 = new MyPromise((resolve, reject) => {
try {
const newValue = fn1(this.value)
resolve(newValue)
} catch (err) {
reject(err)
}
})
return p1
}
if (this.state === 'rejected') {
const p1 = new MyPromise((resolve, reject) => {
try {
const newReason = fn2(this.reason)
reject(newReason)
} catch (err) {
reject(err)
}
})
return p1
}
}
// 就是 then 的一个语法糖,简单模式
catch(fn) {
return this.then(null, fn)
}
}
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 里面做 ++
// 不能用 index
resolvedCount++
if (resolvedCount === length) {
// 已经遍历到了最后一个 promise
resolve(result)
}
}).catch(err => {
reject(err)
})
})
})
return p1
}
MyPromise.race = function (promiseList = []) {
let resolved = false // 标记
const p1 = new Promise((resolve, reject) => {
promiseList.forEach(p => {
p.then(data => {
if (!resolved) {
resolve(data)
resolved = true
}
}).catch((err) => {
reject(err)
})
})
})
return p1
}