手写
/**
* state = 'fullfilled' 执行resolve
* state = 'rejected' 执行reject
*
* state = 'fullfilled'
* 如果callback 不是函数 --> resolve(this.value)
* const x = callback(this.value)
* 如果 x 不是promise对象 --> resolve(x) or reject(x) 和当前状态保持一致
* 如果 x 是promise对象 --> x.then(resolve, reject)
*/
// new Promise((resolve, reject) => {
//
// })
type Executor = (resolve: Function, reject: Function) => any
// p.then(res => alert(res))
type ThenCB = (res: any) => any
type State = 'pending' | 'success' | 'fail'
type Item = {
state: State,
thenCB: ThenCB,
nextPromiseResolve: Function,
nextPromiseReject: Function
}
export default class MyPromise {
_state: State
_value: any
list: Item[]
constructor(executor: Executor) {
this._state = 'pending'
this._value = undefined
this.list = []
try {
executor(this._resolve.bind(this), this._reject.bind(this))
} catch (error) {
this._reject(error)
console.error(error)
}
}
static resolve(value?) {
// 状态吸收
// const p6 = MyPromise.reject('err msg p6')
// const p7 = MyPromise.resolve(p6)
// p7.catch(err => console.log(err))
if (likePromise(value)) {
return value
}
return new MyPromise(resolve => resolve(value))
}
static reject(reason?) {
return new MyPromise((_, reject) => reject(reason))
}
static all(promises) {
return new MyPromise((resolve, reject) => {
const values = []
let count = 0
const add = (i, v) => {
values[i] = v
count++
if (count === promises.length) resolve(values)
}
promises.forEach((p, i) => {
MyPromise.resolve(p).then(
res => add(i, res),
rej => reject(rej)
)
// 其实可以写成下面这样, 但p就必须是promise对象,不然会出错
// p.then(
// res => add(i, res),
// rej => reject(rej)
// )
})
})
}
static race(promises: MyPromise[]) {
return new MyPromise((resolve, reject) => {
promises.forEach(p => {
p.then(resolve as ThenCB, reject as ThenCB)
})
})
}
finally(callback: Function) {
return this.then(
res => {
callback()
return res
},
err => {
callback()
throw err
}
)
}
catch(onRejected) {
return this.then(null, onRejected)
}
then(onResolve?: ThenCB, onReject?: ThenCB) {
return new MyPromise((resolve, reject) => {
this.addItem('success', onResolve, resolve, reject)
this.addItem('fail', onReject, resolve, reject)
this.runItems() // Promis.resolve().then(() => alert(1))
})
}
runItems() {
if (this._state === 'pending') {
return
}
// then的回调函数执行完一定要删除, 防止反复执行
// const p = Promise.resolve()
// p.then(() => {console.log(1)})
// p.then(() => {console.log(2)})
while (this.list.length) {
const item = this.list.shift()
this.runOneItem(item)
}
}
runOneItem(item: Item) {
const { state, thenCB, nextPromiseReject, nextPromiseResolve } = item;
if (state !== this._state) {
return
}
pushToTask(() => {
// 透传
if (!thenCB) {
state === 'success' ?
nextPromiseResolve(this._value) :
nextPromiseReject(this._value)
return
}
try {
const x = thenCB(this._value)
// 状态吸收
// const p1 = Promise.reject(1)
// const p2 = Promise.resolve(2).then(() => p1)
likePromise(x) === true
? x.then(nextPromiseResolve, nextPromiseReject)
: nextPromiseResolve(x)
} catch (e) {
nextPromiseReject(e)
console.error(e)
}
})
}
addItem(state: State, thenCB: ThenCB, nextPromiseResolve: Function, nextPromiseReject: Function) {
this.list.push({
state,
thenCB,
nextPromiseResolve,
nextPromiseReject
})
}
_resolve(value?: any) {
this.setState('success', value)
}
_reject(value?: any) {
this.setState('fail', value)
}
setState(state: State, value: any) {
if (this._state !== 'pending') {
return // 状态更改后就不能变了
}
// 状态吸收
// const p1 = MyPromise.reject('err msg ...')
// const p2 = new MyPromise(res => res(p1))
// p2.catch(err => console.log(err))
if (likePromise(value)) {
value.then(this._resolve.bind(this), this._reject.bind(this))
return
}
this._state = state
this._value = value
this.runItems()
}
}
function isNodeEnv() {
if (globalThis.process && globalThis.process.nextTick) {
return true
}
return false
}
function pushToMicroTask(cb: any) {
const ob = new MutationObserver(cb)
const div = document.createElement('div')
ob.observe(div, {childList: true}) // 监听div, 发生变化就执行cb
div.innerHTML = '1'
}
export function pushToTask(callback) {
// node 环境用 nextTick
if (isNodeEnv()) {
globalThis.process.nextTick(callback)
return
}
// 浏览器环境且支持 MutationObserver
if (MutationObserver) {
pushToMicroTask(callback)
return
}
setTimeout(callback)
}
function isFn(v: any) {
return typeof v === 'function'
}
function isObj(v:any) {
return typeof v === 'object' && v !== null
}
function likePromise(p: any) {
if (
(isObj(p) || isFn(p)) && p.then && isFn(p.then)
) {
return true
}
return false
}
手写工具函数
实现微队列
- node 环境使用 process.nextTick
- 浏览器环境使用 MutationObserver
function isNodeEnv() {
if (process && process.nextTick) {
return true
}
return false
}
// 观察器的回调函数在微队列中
function pushToMicroTask(cb: any) {
const ob = new MutationObserver(cb)
const div = document.createElement('div')
ob.observe(div, {childList: true}) // 监听div, 发生变化就执行cb
div.innerHTML = '1'
}
export function pushToTask(callback) {
// node 环境用 nextTick
if (isNodeEnv()) {
process.nextTick(callback)
return
}
// 浏览器环境且支持 MutationObserver
if (MutationObserver) {
pushToMicroTask(callback)
return
}
setTimeout(callback)
}
实现promiseLike
判断条件
- 是一个对象
- 有then方法
function isFn(v: any) {
return typeof v === 'function'
}
function isObj(v:any) {
return typeof v === 'object' && v !== null
}
function likePromise(p: any) {
if (
(isObj(p) || isFn(p)) && p.then && isFn(p.then)
) {
return true
}
return false
}
实现Promise.all
Promise.all = function (arr) {
return new Promise((resolve, reject) => {
const values = []
let count = 0
const add = (i, v) => {
values[i] = v
count++
if (count === promises.length) resolve(values)
}
arr.forEach((p, i) => {
// 其实可以写成下面这样, 但p就必须是promise对象,不然会出错
// p.then(
// res => add(i, res),
// rej => reject(rej)
// )
Promise.resolve(p).then(
res => add(i, res),
err => reject(err)
)
})
})
}
实现catch
catch(onRejected) {
return this.then(null, onRejected)
}
实现finally
finally(callback: Function) {
return this.then(
res => {
callback()
return res
},
err => {
callback()
throw err
}
)
}
实现Promise.resolve
static resolve(value?) {
// 状态吸收
// const p6 = MyPromise.reject('err msg p6')
// const p7 = MyPromise.resolve(p6)
// p7.catch(err => console.log(err))
if (value instanceof MyPromise) {
return value
}
let resolve, reject
const p = new MyPromise((reso, reje) => {
resolve = reso
reject = reje
})
if (likePromise(value)) {
value.then(resolve, reject)
}
else {
resolve(value)
}
return p
}
实现Promise.reject
static reject(reason?) {
return new MyPromise((_, reject) => reject(reason))
}
async await
return
return undefind
async function fn1() {
console.log(111)
}
翻译
function fn1() {
return new Promise(resolve => {
console.log(111)
resolve(undefind)
})
}
return 123
async function fn1() {
return 123
}
翻译
function fn1() {
return new Promise(resolve => resolve(123))
}
注意: 不能翻译成这样
function fn1() {
return Promise.resolve(123)
}
原因如下:
const p1 = Promise.resolve(1)
async function fn() {
return p1
}
const p2 = fn()
console.log(p1 === p2) // false
const p1 = Promise.resolve(1)
function fn() {
return new Promise(resolve => resolve(p1))
}
const p2 = fn()
console.log(p1 === p2) // false
const p1 = Promise.resolve(1)
function fn() {
return Promise.resolve(p1) // 相当于: return p1
}
const p2 = fn()
console.log(p1 === p2) // true
throw error
async function fn1() {
throw 'err info ...'
}
翻译
function fn1() {
return Promise.reject('err info ...')
}
也可以这样写, 原因去看Promise.reject源码
function fn1() {
return new Promise((_, reject) => reject('err info ...'))
}
async中的状态吸收
async function fn1() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(123)
}, 1000)
})
}
翻译
function fn1() {
const p = new Promise((resolve) => {
setTimeout(() => {
resolve(123)
}, 1000)
})
return new Promise(resolve => resolve(p))
}
await
案例1
async function m(){
const n = await 1;
console.log(n);
// return undefind
}
m();
console.log(2);
翻译
function m(){
return new Promise(resolve => {
Promise.resolve(1).then(n =>{
console.log(n)
resolve(undefind)
})
})
}
m();
console.log(2);
// 答案: 2,1
案例2
- 注意
setTimeout前面有一个await - 搞不懂就去看上面的状态吸收, 以及async await
async function async1() {
console.log(1)
await async2()
console.log(2)
}
async function async2() {
await setTimeout(() => {
Promise.resolve().then(() => console.log(3))
console.log(4)
}, 0)
}
async function async3() {
Promise.resolve().then(() => {
console.log(6)
})
}
async1()
console.log(7)
async3()
翻译
async function async1() {
console.log(1)
async2().then(() => {
console.log(2)
})
}
function async2() {
return new Promise(resolve => {
const timeId = setTimeout(() => {
Promise.resolve().then(() => console.log(3))
console.log(4)
}, 0)
Promise.resolve(timeId).then(() => resolve(undefined))
})
}
async function async3() {
Promise.resolve().then(() => {
console.log(6)
})
}
async1()
console.log(7)
async3()
// 答案: const res = [1, 7, 6, 2, 4, 3]
知识点
// fn1 === fn2
async function fn1() {
return 1
}
// 相当于
function fn2() {
return new Promise(resolve => {
resolve(1)
})
}
// fn1 === fn2 === fn3 === fn4 === fn5
async function fn1() {
return await 1
}
// 相当于
async function fn2() {
return await Promise.resolve(1)
}
// 相当于
async function fn3() {
const res = await Promise.resolve(1)
return res
}
// 相当于
function fn4() {
return new Promise(resolve => {
Promise.resolve(1).then(res => resolve(res))
})
}
// 相当于
function fn5() {
return new Promise(resolve => {
Promise.resolve(1).then(resolve)
})
}
例3
async function async1() {
console.log(1)
await async2()
console.log(2)
}
// 和例1唯一的区别: setTimeout 前面没有await
async function async2() {
setTimeout(() => {
Promise.resolve().then(() => console.log(3))
console.log(4)
}, 0)
}
async function async3() {
Promise.resolve().then(() => {
console.log(6)
})
}
async1()
console.log(7)
async3()
翻译
async function async1() {
console.log(1)
async2().then(() => console.log(2))
}
function async2() {
return new Promise(resolve => {
setTimeout(() => {
Promise.resolve().then(() => console.log(3))
console.log(4)
}, 0)
resolve(undefined)
})
}
async function async3() {
Promise.resolve().then(() => {
console.log(6)
})
}
async1()
console.log(7)
async3()
// 答案: const res = [1, 7, 2, 6, 4, 3]
例4
async function async1() {
console.log(1)
await async2()
console.log(2)
}
async function async2() {
await (async () => {
await (() => {
console.log(3)
})()
console.log(4)
})()
}
async function async3() {
Promise.resolve().then(() => {
console.log(6)
})
}
async1()
console.log(7)
async3()
翻译
async function async1() {
console.log(1)
async2().then(() => console.log(2))
}
async function async2() {
const p = (() => {
return new Promise(resolve => {
const res = (() => {
console.log(3)
})()
Promise.resolve(res).then(() => {
console.log(4)
resolve(undefined)
})
})
})()
return new Promise(resolve => {
p.then(() => resolve(undefined))
})
}
async function async3() {
Promise.resolve().then(() => {
console.log(6)
})
}
async1()
console.log(7)
async3()
// 答案 const res = [1, 3, 7, 4, 6, 2]
例5
async function async1() {
console.log(1)
await async2()
console.log(2)
}
async function async2() {
await (async () => {
Promise.resolve().then(() => console.log(3))
console.log(4)
})()
}
async function async3() {
Promise.resolve().then(() => {
console.log(6)
})
}
async1()
console.log(7)
async3()
翻译
function async1() {
console.log(1)
async2().then(() => {
console.log(2)
async1Resolve(undefined) // 伪代码
})
}
async function async2() {
const p = (() => {
Promise.resolve().then(() => console.log(3))
console.log(4)
resolve(undefined) // 伪代码
})()
p.then(() => async2Resolve(undefined))// 伪代码
}
async function async3() {
Promise.resolve().then(() => {
console.log(6)
})
}
async1()
console.log(7)
async3()
// 答案 const res = [1, 4,7,3,6,2]
状态吸收
状态吸收的场景
// 状态吸收1
const p6 = MyPromise.resolve('... p6')
const p7 = MyPromise.reject(p6)
p7.then(err => console.log(err))
// 状态吸收2
const p3 = MyPromise.reject('err msg p3')
const p4 = MyPromise.resolve().then(() => p3)
p4.catch(err=> console.log(err))
// 状态吸收3
const p1 = MyPromise.reject('err msg ...')
const p2 = new MyPromise(res => res(p1))
p2.catch(err => console.log(err))
第一题
const p1 = new Promise(resolve => resolve(1))
const p2 = new Promise(resolve => resolve(p1))
console.log(p1)
console.log(p2)
答案
const p1 = new Promise(resolve => resolve(1))
// resolve(p1)触发状态吸收
// 添加一个微任务 () => p1.then(resolve, reject)
// console.log(p2) 执行完成后才会执行微任务, 所以p2此时的状态为pending
const p2 = new Promise(resolve => resolve(p1))
console.log(p1) // Promise { 1 }
console.log(p2) // Promise { <pending> }
第二题
async function fn1() {
console.log(1)
await fn2()
console.log("AAA")
}
function fn2() {
return Promise.resolve(2)
}
fn1()
Promise.resolve()
.then(() => console.log(3))
.then(() => console.log(4))
.then(() => console.log(5))
翻译
async function fn1() {
console.log(1)
fn2().then(() => console.log("AAA"))
}
function fn2() {
return Promise.resolve(2)
}
fn1()
Promise.resolve()
.then(() => console.log(3))
.then(() => console.log(4))
.then(() => console.log(5))
答案分析
// 执行: fn2().then(() => console.log("AAA"))
// 添加微任务: () => console.log("AAA")
[
() => console.log("AAA")
]
// 执行: Promise.resolve().then(() => console.log(3))
// 添加微任务: () => console.log(3)
[
() => console.log("AAA"),
() => console.log(3)
]
// 执行 () => console.log("AAA") 没有产生新的微任务
// 执行 () => console.log(3)
// 添加微任务 () => console.log(4)
[
() => console.log(4)
]
//执行 () => console.log(4)
//添加微任务 () => console.log(5)
[
() => console.log(5)
]
// 答案: 1, 'AAA', 3, 4, 5
第三题
async function fn1() {
console.log(1)
await fn2()
console.log("AAA")
}
// 与第二题不同的地方fn2
async function fn2() {
return Promise.resolve(2)
}
fn1()
Promise.resolve()
.then(() => console.log(3))
.then(() => console.log(4))
.then(() => console.log(5))
翻译
async function fn1() {
console.log(1)
fn2().then(() => console.log('AAA'))
}
function fn2() {
return new Promise((resolve) => {
const p1 = Promise.resolve(2)
resolve(p1)
})
}
fn1()
Promise.resolve()
.then(() => console.log(3))
.then(() => console.log(4))
.then(() => console.log(5))
答案分析
// 同步任务
[
console.log(1)
]
// 微任务
[
// 谁生成的该微任务:
// resolve(p1)
() => p1.then(resolve)
// 谁生成的该微任务:
// Promise.resolve().then(()=>console.log(3))
() => console.log(3)
// 谁生成的该微任务:
// () => p1.then(resolve)
() => resolve()
// 谁生成的该微任务:
// () => console.log(3)
() => console.log(4)
// 谁生成的该微任务:
// () => resolve()
() => console.log("AAA")
// 谁生成的该微任务:
// () => console.log(4)
() => console.log(5)
]
// 打印结果为: 1, 3, 4, 'AAA', 5
第四题
const p1 = new Promise((resolve) => resolve(1))
const p2 = new Promise((resolve) => resolve(p1))
p2
.then(() => console.log(1))
.then(() => console.log(2))
.then(() => console.log(3))
p1
.then(() => console.log(4))
.then(() => console.log(5))
.then(() => console.log(6))
答案
// 微队列
[
() => p1.then(resolve),
() => console.log(4),
() => resolve(),// 添加者:() => p1.then(resolve),
() => console.log(5),//添加者:() => console.log(4)
() => console.log(1),//添加者:() => resolve()
() => console.log(6),//添加者:() => console.log(5)
() => console.log(2),//添加者:() => console.log(1)
() => console.log(3),//添加者:() => console.log(2)
]
// 4, 5, 1, 6, 2, 3
第五题
Promise.resolve()
.then(() => {
console.log(0)
return Promise.resolve(4)
})
.then(res => console.log(res))
Promise.resolve()
.then(() => console.log(1))
.then(() => console.log(2))
.then(() => console.log(3))
.then(() => console.log(5))
答案
const microTask = [
() => {
console.log(0)
return Promise.resolve(4) // return p4
},
() => console.log(1),
() => p4.then(resolve),
() => console.log(2),
() => resolve(4),
() => console.log(3),
(res) => console.log(res), // res=4
() => console.log(5),
]
// 答案: 0,1,2,3,4,5
其他面试题
交替执行
Promise.resolve()
.then(() => console.log(1))
.then(() => console.log(2))
.then(() => console.log(3));
Promise.resolve()
.then(() => console.log(10))
.then(() => console.log(20))
.then(() => console.log(30));
Promise.resolve()
.then(() => console.log(100))
.then(() => console.log(200))
.then(() => console.log(300));
答案
// 1
// 10
// 100
// 2
// 20
// 200
// 3
// 30
// 300
catch error
案例1
Promise.resolve()
.then(res => {
console.log('---------- 111') // √
throw new Error()
})
.catch(err => {
console.log('---------- 222') // √
})
.then(res => {
console.log('---------- 333') // √
})
案例2
Promise.resolve()
.then(res => {
console.log('---------- 111') // √
throw new Error()
})
.catch(err => {
console.log('---------- 222') // √
})
.catch(res => {
console.log('---------- 333')
})
事件循环
setTimeout(() => {
console.log(1)
})
const p = new Promise(resolve => {
console.log(2)
resolve(3)
Promise.resolve(4).then(console.log)
console.log(5)
}).then(console.log)
console.log(6)
解析
// 步骤1: 创建 MyPromise 实例,执行executor函数
console.log(2); // 输出: 2
// 步骤2: 调用 resolve(3)
// 注意:此时 Promise 的 then 方法尚未注册
// 步骤3: 创建原生 Promise 并注册 then 回调
// ✅ 将 console.log(4) 加入微任务队列
Promise.resolve(4).then(console.log);
答案
const res = [2, 5, 6, 4, 3, 1]
const macroTask = [
() => console.log(1),
]
const microTask = [
() => console.log(4),
() => console.log(3),
]
构造函数
new Promise((resolve, reject) => {
reject(1)
console.log(2)
resolve(3)
console.log(4)
})
.then(res => console.log(res))
.catch(err => console.log(err))
try {
new Promise((resolve, reject) => {
throw 6
})
.then(console.log)
.catch(err => console.log(8))
} catch (error) {
console.log(error)
}
// 答案
const res = [2, 4, 1, 8]
const microTask = [
err => console.log(err),// 1
err => console.log(8)//
]
微任务
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
console.log(2);
})
promise.then(() => {
console.log(3);
})
console.log(4);
// 答案: 1,2,4,3
宏任务+微任务
const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(()=>{
console.log(2)
resolve(null);
console.log(3);
})
})
promise.then(() => {
console.log(4);
})
console.log(5);
// 答案: 1,5,2,3,4
透传
例1
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
const promise2 = promise1.catch(() => {
return 2;
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
console.log('promise1', promise1)
console.log('promise2', promise2)
}, 2000)
翻译
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
const promise2 = promise1.then(
null,
() => 2
)
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
console.log('promise1', promise1)
console.log('promise2', promise2)
}, 2000)
// 答案:
// promise1 Promise { <pending> }
// promise2 Promise { <pending> }
// promise1 Promise { 1 }
// promise2 Promise { 1 }
例2
Promise.resolve()
.then(res => {
console.log('---------- 111') // √
})
.catch(err => {
console.log('---------- 222')
})
.then(res => {
console.log('---------- 333') // √
})
解析
Promise.resolve()
.then(res => console.log('---------- 111'))// √
.then(null, err => console.log('---------- 222'))
.then(res => console.log('---------- 333'))// √
例3
const p1 = Promise.reject()
.then(() => console.log(1))
.then(() => console.log(2))
.catch(() => console.log(3));
const p2 = Promise.resolve()
.then(() => console.log(4))
.then(() => console.log(5));
解析
// 不会看源码
[
reject1,
console.log(4),
reject2
console.log(5)
console.log(3)
]
// 答案: 4, 5, 3