1. 构造函数
- 定义类
- 添加构造函数,接收 func 函数参数
- 定义 resolve,reject
- 执行回调函数,传入自定义的 resolve 和 reject
class MyPromise {constructor(func) {const resolve = (result) => {console.log('run', result)}const reject = (result) => {console.log('run', reject)}func(resolve, reject)}
}// -----------------测试------------------
const p = new MyPromise((resolve, reject)=> {resolve('success')// reject('error')
})
2. 状态及原因
- 添加状态及原因
- resolve 和 reject 函数调整状态原因和状态不可逆
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'class MyPromise {state = PENDINGresult = undefinedconstructor(func) {const resolve = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = result}}const reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = result}}func(resolve, reject)
}
}// -----------------测试------------------
const p = new MyPromise((resolve, reject) => {resolve('success')reject('error')
})
3. then 方法
- 添加 then 方法
- 函数参数的类型按断(参考文档)
- 根据状态执行 then 的函数参数回调
3.1 成功和失败的回调
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'class MyPromise {state = PENDING
result = undefinedconstructor(func) {const resolve = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = result}}const reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = result}}func(resolve, reject)
}then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled: x => xonRejected = typeof onRejected === 'function'? onRejected: x => {throw x}if (this.state === FULFILLED) {onFulfilled(this.result);} else if (this.state === REJECTED) {onRejected(this.result);}
}
}// -----------------测试------------------
const p = new MyPromise((resolve, reject) => {// resolve('success')reject('error111')
})
p.then(res => {console.log('成功回调:', res)
}, 'string')
3.2 异步和多次调用
- 定义实例属性 #handlers
- then 方法,状态为 pending 保存回调函数
- 构造函数取出并执行保存的回调函数
const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'class MyPromise {/*** 状态* @type {string}*/state = PENDING/*** 原因* @type {*}*/result = undefined/*** 保存回调函数的对象数组* @type {[]}*/#handlers = []constructor(func) {/*** 构造成功的 Promise* @param result*/const resolve = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = resultthis.#handlers.forEach(({onFulfilled}) => {onFulfilled(this.result)})}}/*** 构造失败的 Promise* @param result*/const reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = resultthis.#handlers.forEach(({onRejected}) => {onRejected(this.result)})}}func(resolve, reject)}/*** then 方法* @param onFulfilled 成功回调函数* @param onRejected 失败回调函数*/then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => xonRejected = typeof onRejected === 'function' ? onRejected : x => {throw x}if (this.state === FULFILLED) {onFulfilled(this.result);} else if (this.state === REJECTED) {onRejected(this.result);} else if (this.state === PENDING) {this.#handlers.push({onFulfilled, onRejected})}}}// -----------------测试------------------const p = new MyPromise((resolve, reject) => {setTimeout(() => {// resolve('success')reject('error')}, 2000)})p.then(res => {console.log('成功回调:', res)}, err => {console.log('失败回调', err)})p.then(res => {console.log('成功回调:', res)}, err => {console.log('失败回调', err)})
4. 异步任务
4.1 使用核心 api
-
queueMicrotask
:新式浏览器均支持,node11开始支持,ie不支持 -
MutationObserver
:新式浏览器均支持,ie11开始支持 -
setTimeout
:浏览器支持,node支持
// ------------- 异步任务1 queueMicrotask -------------
// node v11 ie 不支持
// console.log('top')
queueMicrotask(() => {// ....
})
// console.log('bottom')// ------------- 异步任务2 MutationObserver -------------
// node 不支持 ie11
console.log('top')
// 创建并返回一个新的观察器,它会在触发指定 DOM 事件时,调用指定的回调函数
const obs = new MutationObserver(() => {console.log('MutationObserver-run')
})
// 创建div
const divNode = document.createElement('div')
// 监听创建的div ,监听子节点改变
obs.observe(divNode, { childList: true })
// 修改内容触发回调函数
divNode.innerText = 'itheima 666'
console.log('bottom')
4.2 异步任务
- 定义异步任务函数 api
- 异步任务封装 onFulfilled 和 onRejected 函数
const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'/*** 异步执行任务(底层异步函数放入微任务,最后用宏任务 setTimeout 兜底)* @param callback*/function runAsynctask(callback) {// 如果浏览器不支持则为 undefinedif (typeof queueMicrotask === 'function') {queueMicrotask(callback)} else if (typeof MutationObserver === 'function') {const obs = new MutationObserver(callback)const divNode = document.createElement('div')obs.observe(divNode, {childList: true})divNode.innerText = 'heo'} else {setTimeout(callback, 0);}}class MyPromise {/*** 状态* @type {string}*/state = PENDING/*** 原因* @type {*}*/result = undefined/*** 保存回调函数的对象数组* @type {[]}*/#handlers = []constructor(func) {/*** 构造成功的 Promise* @param result*/const resolve = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = resultthis.#handlers.forEach(({onFulfilled}) => {onFulfilled(this.result)})}}/*** 构造失败的 Promise* @param result*/const reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = resultthis.#handlers.forEach(({onRejected}) => {onRejected(this.result)})}}func(resolve, reject)}/*** then 方法* @param onFulfilled 成功回调函数* @param onRejected 失败回调函数*/then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => xonRejected = typeof onRejected === 'function' ? onRejected : x => {throw x}if (this.state === FULFILLED) {runAsynctask(() => {onFulfilled(this.result);})} else if (this.state === REJECTED) {runAsynctask(() => {onRejected(this.result);})} else if (this.state === PENDING) {this.#handlers.push({onFulfilled: () => {runAsynctask(() => {onFulfilled(this.result)})}, onRejected: () => {runAsynctask(() => {onRejected(this.result)})}})}}}// -----------------测试------------------console.log('top')const p = new MyPromise((resolve, reject) => {resolve('success')})p.then(res=> {console.log(res)})console.log('bottom')
5. 链式编程
5.1 处理 fulfilled 状态
5.1.1 处理异常和普通函数
- 返回新的 Promise 实例
- 获取成功回调函数结果,并传入新的 resolve 或者 reject
<script>const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'/*** 异步执行任务(底层异步函数放入微任务,最后用宏任务 setTimeout 兜底)* @param callback*/function runAsynctask(callback) {// 如果浏览器不支持则为 undefinedif (typeof queueMicrotask === 'function') {queueMicrotask(callback)} else if (typeof MutationObserver === 'function') {const obs = new MutationObserver(callback)const divNode = document.createElement('div')obs.observe(divNode, { childList: true })divNode.innerText = 'heo'} else {setTimeout(callback, 0);}}class MyPromise {/*** 状态* @type {string}*/state = PENDING/*** 原因* @type {*}*/result = undefined/*** 保存回调函数的对象数组* @type {[]}*/#handlers = []constructor(func) {/*** 构造成功的 Promise* @param result*/const resolve = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = resultthis.#handlers.forEach(({ onFulfilled }) => {onFulfilled(this.result)})}}/*** 构造失败的 Promise* @param result*/const reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = resultthis.#handlers.forEach(({ onRejected }) => {onRejected(this.result)})}}func(resolve, reject)}/*** then 方法* @param onFulfilled 成功回调函数* @param onRejected 失败回调函数*/then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => xonRejected = typeof onRejected === 'function' ? onRejected : x => {throw x}const p2 = new MyPromise((resolve,reject)=> {if (this.state === FULFILLED) {runAsynctask(() => {try {const x = onFulfilled(this.result);resolve(x)} catch (e) {reject(e)}})} else if (this.state === REJECTED) {runAsynctask(() => {onRejected(this.result);})} else if (this.state === PENDING) {this.#handlers.push({onFulfilled: () => {runAsynctask(() => {onFulfilled(this.result)})}, onRejected: () => {runAsynctask(() => {onRejected(this.result)})}})}})return p2;}}// -----------------测试------------------const p = new MyPromise((resolve, reject) => {resolve('1')})p.then(res => {console.log('p1', res)throw 'throw-error'return '2'}).then(res=> {console.log('p2',res)},err=> {console.log('p2',err)})</script>
5.1.2 处理返回 Promise
返回了promise对象,在源码中对这个返回的promise对象进行链式调用,这样就能直接在then的里面获取到结果,其实就是源码帮了个忙,不用开发者自己再链式调用。
- 判断是否返回 Promise
- 调用 then 方法,进行 resolve 或 reject 处理
<script>const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'/*** 异步执行任务(底层异步函数放入微任务,最后用宏任务 setTimeout 兜底)* @param callback*/function runAsynctask(callback) {// 如果浏览器不支持则为 undefinedif (typeof queueMicrotask === 'function') {queueMicrotask(callback)} else if (typeof MutationObserver === 'function') {const obs = new MutationObserver(callback)const divNode = document.createElement('div')obs.observe(divNode, {childList: true})divNode.innerText = 'heo'} else {setTimeout(callback, 0);}}class MyPromise {/*** 状态* @type {string}*/state = PENDING/*** 原因* @type {*}*/result = undefined/*** 保存回调函数的对象数组* @type {[]}*/#handlers = []constructor(func) {/*** 构造成功的 Promise* @param result*/const resolve = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = resultthis.#handlers.forEach(({onFulfilled}) => {onFulfilled(this.result)})}}/*** 构造失败的 Promise* @param result*/const reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = resultthis.#handlers.forEach(({onRejected}) => {onRejected(this.result)})}}func(resolve, reject)}/*** then 方法* @param onFulfilled 成功回调函数* @param onRejected 失败回调函数*/then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => xonRejected = typeof onRejected === 'function' ? onRejected : x => {throw x}const p2 = new MyPromise((resolve, reject) => {if (this.state === FULFILLED) {runAsynctask(() => {try {const x = onFulfilled(this.result);if (x instanceof MyPromise) {x.then(res => {resolve(res)}, err => {reject(err)})} else {resolve(x);}} catch (e) {reject(e)}})} else if (this.state === REJECTED) {runAsynctask(() => {onRejected(this.result);})} else if (this.state === PENDING) {this.#handlers.push({onFulfilled: () => {runAsynctask(() => {onFulfilled(this.result)})}, onRejected: () => {runAsynctask(() => {onRejected(this.result)})}})}})return p2;}}// -----------------测试------------------const p = new MyPromise((resolve, reject) => {resolve('1')})p.then(res => {return new MyPromise((resolve, reject) => {resolve(2)// reject('error')})}).then(res => {console.log('p2', res)}, err => {console.log('p2', err)})
</script>
5.1.3 处理重复引用(手动 return then 的返回值)
- 判断是否为重复引用
- 抛出异常
<script>const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'/*** 异步执行任务(底层异步函数放入微任务,最后用宏任务 setTimeout 兜底)* @param callback*/function runAsynctask(callback) {// 如果浏览器不支持则为 undefinedif (typeof queueMicrotask === 'function') {queueMicrotask(callback)} else if (typeof MutationObserver === 'function') {const obs = new MutationObserver(callback)const divNode = document.createElement('div')obs.observe(divNode, {childList: true})divNode.innerText = 'heo'} else {setTimeout(callback, 0);}}class MyPromise {/*** 状态* @type {string}*/state = PENDING/*** 原因* @type {*}*/result = undefined/*** 保存回调函数的对象数组* @type {[]}*/#handlers = []constructor(func) {/*** 构造成功的 Promise* @param result*/const resolve = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = resultthis.#handlers.forEach(({onFulfilled}) => {onFulfilled(this.result)})}}/*** 构造失败的 Promise* @param result*/const reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = resultthis.#handlers.forEach(({onRejected}) => {onRejected(this.result)})}}func(resolve, reject)}/*** then 方法* @param onFulfilled 成功回调函数* @param onRejected 失败回调函数*/then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => xonRejected = typeof onRejected === 'function' ? onRejected : x => {throw x}const p2 = new MyPromise((resolve, reject) => {if (this.state === FULFILLED) {runAsynctask(() => {try {const x = onFulfilled(this.result);if (x === p2) {throw new TypeError('Chaining cycle detected for promise #<Promise>')}if (x instanceof MyPromise) {x.then(res => {resolve(res)}, err => {reject(err)});} else {resolve(x);}} catch (e) {reject(e)}})} else if (this.state === REJECTED) {runAsynctask(() => {onRejected(this.result);})} else if (this.state === PENDING) {this.#handlers.push({onFulfilled: () => {runAsynctask(() => {onFulfilled(this.result)})}, onRejected: () => {runAsynctask(() => {onRejected(this.result)})}})}})return p2;}}// -----------------测试------------------// TypeError: Chaining cycle detected for promise #<Promise>const p = new MyPromise((resolve, reject) => {resolve('1')})const p2 = p.then(res=> {return p2;})p2.then(res=>{}, err => {console.log('err:', err)})
</script>
5.2 处理 rejected 状态
步骤同处理 fulfilled 状态。
优化:
- 处理异常
- 抽取 resolvePromise 函数(处理返回 Promise 和其他值的情况)
- 调用函数
<script>const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'/*** 异步执行任务(底层异步函数放入微任务,最后用宏任务 setTimeout 兜底)* @param callback*/function runAsynctask(callback) {// 如果浏览器不支持则为 undefinedif (typeof queueMicrotask === 'function') {queueMicrotask(callback)} else if (typeof MutationObserver === 'function') {const obs = new MutationObserver(callback)const divNode = document.createElement('div')obs.observe(divNode, {childList: true})divNode.innerText = 'heo'} else {setTimeout(callback, 0);}}/*** 处理返回 Promise 和其他值的情况* @param p2 then 的返回 Promise 结果* @param x 成功或者失败回调函数的结果* @param resolve 构造成功的 Promise* @param reject 构造失败的 Promise*/function resolvePromise(p2, x, resolve, reject) {if (x === p2) {throw new TypeError('Chaining cycle detected for promise #<Promise>')}if (x instanceof MyPromise) {x.then(res => {resolve(res)}, err => {reject(err)});} else {resolve(x)}}class MyPromise {/*** 状态* @type {string}*/state = PENDING/*** 原因* @type {*}*/result = undefined/*** 保存回调函数的对象数组* @type {[]}*/#handlers = []constructor(func) {/*** 构造成功的 Promise* @param result*/const resolve = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = resultthis.#handlers.forEach(({onFulfilled}) => {onFulfilled(this.result)})}}/*** 构造失败的 Promise* @param result*/const reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = resultthis.#handlers.forEach(({onRejected}) => {onRejected(this.result)})}}func(resolve, reject)}/*** then 方法* @param onFulfilled 成功回调函数* @param onRejected 失败回调函数*/then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => xonRejected = typeof onRejected === 'function' ? onRejected : x => {throw x}const p2 = new MyPromise((resolve, reject) => {if (this.state === FULFILLED) {runAsynctask(() => {try {const x = onFulfilled(this.result);resolvePromise(p2, x, resolve, reject)} catch (e) {reject(e)}})} else if (this.state === REJECTED) {runAsynctask(() => {try {const x = onRejected(this.result);resolvePromise(p2, x, resolve, reject)} catch (e) {reject(e)}})} else if (this.state === PENDING) {this.#handlers.push({onFulfilled: () => {runAsynctask(() => {onFulfilled(this.result)})}, onRejected: () => {runAsynctask(() => {onRejected(this.result)})}})}})return p2;}}// -----------------测试------------------// TypeError: Chaining cycle detected for promise #<Promise>const p = new MyPromise((resolve, reject) => {reject(1)})const p2 = p.then(undefined, err => {// throw 'err'// return p2return 2// return new MyPromise((resolve, reject)=> {// resolve('MyPromise-2')// reject('MyPromise-error')// })})p2.then(res => {console.log('p2-res:', res)}, err => {console.log('p2-err:', err)})
</script>
5.3 处理 pending 状态
步骤同处理 rejected 状态。
优化:
- 处理异常
- 调用 resolvePromise 函数(处理返回 Promise 和其他值的情况)
<script>const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'/*** 异步执行任务(底层异步函数放入微任务,最后用宏任务 setTimeout 兜底)* @param callback*/function runAsynctask(callback) {// 如果浏览器不支持则为 undefinedif (typeof queueMicrotask === 'function') {queueMicrotask(callback)} else if (typeof MutationObserver === 'function') {const obs = new MutationObserver(callback)const divNode = document.createElement('div')obs.observe(divNode, {childList: true})divNode.innerText = 'heo'} else {setTimeout(callback, 0);}}/*** 处理返回 Promise 和其他值的情况* @param p2 then 的返回 Promise 结果* @param x 成功或者失败回调函数的结果* @param resolve 构造成功的 Promise* @param reject 构造失败的 Promise*/function resolvePromise(p2, x, resolve, reject) {if (x === p2) {throw new TypeError('Chaining cycle detected for promise #<Promise>')}if (x instanceof MyPromise) {x.then(res => {resolve(res)}, err => {reject(err)});} else {resolve(x)}}class MyPromise {/*** 状态* @type {string}*/state = PENDING/*** 原因* @type {*}*/result = undefined/*** 保存回调函数的对象数组* @type {[]}*/#handlers = []constructor(func) {/*** 构造成功的 Promise* @param result*/const resolve = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = resultthis.#handlers.forEach(({onFulfilled}) => {onFulfilled(this.result)})}}/*** 构造失败的 Promise* @param result*/const reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = resultthis.#handlers.forEach(({onRejected}) => {onRejected(this.result)})}}func(resolve, reject)}/*** then 方法* @param onFulfilled 成功回调函数* @param onRejected 失败回调函数*/then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => xonRejected = typeof onRejected === 'function' ? onRejected : x => {throw x}const p2 = new MyPromise((resolve, reject) => {if (this.state === FULFILLED) {runAsynctask(() => {try {const x = onFulfilled(this.result);resolvePromise(p2, x, resolve, reject)} catch (e) {reject(e)}})} else if (this.state === REJECTED) {runAsynctask(() => {try {const x = onRejected(this.result);resolvePromise(p2, x, resolve, reject)} catch (e) {reject(e)}})} else if (this.state === PENDING) {this.#handlers.push({onFulfilled: () => {runAsynctask(() => {try {const x = onFulfilled(this.result)resolvePromise(p2,x,resolve,reject)} catch (e) {reject(e)}})}, onRejected: () => {runAsynctask(() => {try {const x = onRejected(this.result)resolvePromise(p2,x,resolve,reject)} catch (e) {reject(e)}})}})}})return p2;}}// -----------------测试------------------const p = new MyPromise((resolve, reject) => {setTimeout(()=> {resolve(1)},2000)})const p2 = p.then(res=> {// throw 'err'// return p2// return 2return new MyPromise((resolve, reject)=> {setTimeout(()=> {// resolve('resolve-2')reject('reject-2')},2000)})})p2.then(res => {console.log('p2-res:', res)}, err => {console.log('p2-err:', err)})
</script>