这篇博客咱们会学习的有:
catch
,finally
resolve
,reject
,race
,all
,allSettled
,any
首先明确Promise的核心用法
// 实例化 并管理异步任务
const p = new DIYPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
// reject('error')
}, 1000);
})
// then方法获取成功/失败结果
// 参数1:成功时执行的回调函数
// 参数2:失败时执行的回调函数
p.then(res => {
console.log('res:', res)
return 'success2'
}, err => {
console.log('err:', err)
}).then(res2 => {
console.log('res2:', res2)
})
DIYPromise
类,可以用如下的方式实例化resolve
和reject
const p = new DIYPromise((resolve, reject) => {
resolve('success')
// reject('error')
})
DIYPromise
constructor
// 1. 定义类
class DIYPromise{
// 2. 添加构造函数
constructor(func) {
// 3. 定义resolve/reject
const resolve = (result) => {
console.log('resolve-执行啦:', result)
}
const reject = (result) => {
console.log('reject-执行啦:', result)
}
// 4. 执行回调函数
func(resolve, reject)
}
}
手写Promise-构造函数
DIYPromise
,内部添加构造函数constructor
,构造函数需要接收回调函数func
resolve
和reject
func
并将resolve
和reject
传入:func(resolve,reject)
DIYPromise
增加state
属性,只能是如下3个值
pending
:待定,默认状态fulfilled
:已兑现,操作成功rejected
:已拒绝,操作失败DIYPromise
增加result
属性,记录成功/失败原因resolve
或reject
,修改状态,并记录成功/失败原因const p = new DIYPromise((resolve, reject) => {
resolve('success') // pending -> fulfilled
// reject('error') // pending -> rejected
})
p.state // 状态
p.result // 原因
DIYPromise
中定义
state
保存状态,result
成功/失败原因state
的私有方法,修改状态并记录result
state
只有在pending
时,才可以修改,且不可逆const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 1. 添加状态
state = PENDING
// 2. 添加原因
result = undefined
constructor(func) {
// 3. 调整resolve/reject
// 4. 状态不可逆
// 改状态: pending->fulfilled
// 记录原因
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
}
}
// 改状态: pending->rejected
// 记录原因
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
}
}
func(resolve, reject)
}
}
手写Promise-状态、成功or失败原因
pending
,fulfilled
,rejected
DIYPromise
内部定义属性state
和result
分别用来保存状态和原因resolve
时传入具体原因,如果状态为pending
则更改状态并记录兑现原因reject
时传入具体原因,如果状态为pending
则更改状态并记录拒绝原因fulfilled
时触发,并获取成功结果rejected
时触发,并获取失败原因const p = new DIYPromise((resolve, reject) => {
resolve('success')
// reject('error')
})
p.then(res => {
console.log('成功回调:', res)
}, err => {
console.log('失败回调:', err)
})
then
方法,根据不同的状态执行对应的回调函数,并传入result
onFulfilled
,onRejected
时const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 状态
state = PENDING
// 原因
result = undefined
// 构造函数
constructor(func) {
// pending->fulfilled
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
}
}
// pending->rejected
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
}
}
func(resolve, reject)
}
// 1. 添加实例方法
then(onFulfilled, onRejected) {
// 2. 参数判断(参考文档)
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
// 2.1 执行成功回调
// 2.2 执行失败回调
if (this.state === FULFILLED) {
onFulfilled(this.result)
} else if (this.state === REJECTED) {
onRejected(this.result)
}
}
}
手写Promise-then方法-成功和失败回调
then
方法,接收2个回调函数:
onFulfilled
onRejected
onFulfilled
和onRejected
是否为函数,如果不是设置默认值onFulfilled
或onRejected
并传入兑现或拒绝原因then
方法支持多次调用(非链式编程)const p = new DIYPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
// reject('error')
}, 2000);
})
p.then(res => {
console.log('then1:', res)
}, err => {
console.log('then1:', err)
})
p.then(res => {
console.log('then2:', res)
}, err => {
console.log('then2:', err)
})
[]
pending
时resolve
内部reject
内部const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 状态
state = PENDING
// 原因
result = undefined
// 1. 定义实例属性
#handlers = [] // [{onFulfilled,onRejected}...]
// 构造函数
constructor(func) {
// pending->fulfilled
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
// 3. 调用成功回调
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
// pending->rejected
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
// 4. 调用失败回调
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
// then方法
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = 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) {
// 2. 保存回调函数
this.#handlers.push({
onFulfilled, onRejected
})
}
}
}
手写Promise-then方法-异步和多次调用
DIYPromise
添加私有属性#handlers
pending
的回调函数[{onFulfilled,onRejected}...]
resolve
和reject
的逻辑:
resolve
时取出数组#handlers
中的所有onFulfilled
回调函数进行调用reject
时取出数组#handlers
中的所有onRejected
回调函数进行调用top success bottom
console.log('top')
const p = new DIYPromise((resolve, reject) => {
resolve('success')
})
p.then(res => {
console.log(res)
})
console.log('bottom')
这里我们参考vue2的做法:
Promise.then
: 我们是手写Promise,故不选用这个queueMicrotask
:新式浏览器均支持,node11开始支持,ie不支持MutationObserver
:新式浏览器均支持,ie11开始支持setImmediate
: 新式浏览器只有edge支持,ie10开始支持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 = 'javascript 666'
console.log('bottom')
// ------------- 异步任务3 setTimeout -------------
// 这个都熟悉,就不测试了啦
请问可以使用哪些方式开启异步任务:
Promise.then
: 我们是手写Promise,故不选用这个queueMicrotask
:新式浏览器均支持,node11开始支持,ie不支持MutationObserver
:新式浏览器均支持,ie11开始支持setImmediate
: 新式浏览器只有edge支持,ie10开始支持setTimeout
:浏览器支持,node支持runMicrotask
内部执行异步任务runMicrotask
让then
方法的回调函数为异步任务runMicrotask
并传入回调函数queueMicrotask
、MutationObserver
、 setTimeout
并使用即可runMicrotask
开启执行异步任务即可// 1. 定义函数
function runAsynctask(callback) {
// 2. 调用核心api(queueMicrotask,MutationObserver,setTimeout)
if (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 = 'javascript 666'
} else {
setTimeout(callback, 0)
}
}
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 状态
state = PENDING
// 原因
result = undefined
// 回调函数数组
#handlers = [] // [{onFulfilled,onRejected}...]
// 构造函数
constructor(func) {
// pending->fulfilled
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
// pending->rejected
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
// then方法
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
// 3. 使用封装函数
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)
})
}
})
}
}
}
手写Promise-异步任务-函数封装
queueMicrotask
,MutationObserver
api
可以根据实际情况进行调整setTimeout
兜底then
中的逻辑,fulFilled
,rejected
,pending
3种状态时的回调函数,使用封装的函数包装一次then
的链式编程then
的第一个回调函数
const p = new DIYPromise((resolve, reject) => {
resolve(1)
})
p.then(res => {
console.log(res)
// throw 'throw-error'
return 2
}).then(res => {
console.log(res)
}, err => {
console.log(err)
})
then
方法,返回一个新的DIYPromise
对象try-catch
捕获异常,并通过reject
传递onFulfilled
的执行结果,并通过resolve
传递// 执行异步任务
function runAsynctask(callback) {
if (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 = 'itheima666'
} else {
setTimeout(callback, 0)
}
}
/**
* 链式编程-处理异常和普通内容(fulfilled状态)
* 1. 返回新Promise实例
* 2. 获取返回值
* 2.1 处理返回值
* 2.2 处理异常
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 状态
state = PENDING
// 原因
result = undefined
// 回调函数数组
#handlers = [] // [{onFulfilled,onRejected}...]
// 构造函数
constructor(func) {
// pending->fulfilled
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
// pending->rejected
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
// then方法
// 1. 返回新Promise实例
// 2. 获取返回值
// 2.1 处理返回值
// 2.2 处理异常
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
// 1. 返回新Promise实例
const p2 = new HMPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
// 2. 获取返回值
try {
const x = onFulfilled(this.result)
// console.log('x:', x)
// 2.1 处理返回值
resolve(x)
} catch (error) {
// 2.2 处理异常
// console.log('捕获异常:', error)
reject(error)
}
})
}
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
}
}
手写Promie-链式编程-fulfilled状态-返回值+异常
DIYPromise
对象DIYPromise
对象的回调函数中try-catch
捕获异常,出现异常通过reject
传递异常onFulfilled
的执行结果,并通过resolve
传递then
的链式编程then
的第一个回调函数
Promise
const p = new DIYPromise((resolve, reject) => {
resolve(1)
})
p.then(res => {
return new DIYPromise((resolve, reject) => {
resolve(2)
// reject('error')
})
}).then(res => {
console.log('p2:', res) // 2
}, err => {
console.log('p2:', err) // error
})
DIYPromise
实例then
方法依次传入回调函数// 执行异步任务
function runAsynctask(callback) {
if (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 = 'itheima666'
} else {
setTimeout(callback, 0)
}
}
/**
* 链式编程-处理Promise(fulfilled状态)
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 状态
state = PENDING
// 原因
result = undefined
// 回调函数数组
#handlers = [] // [{onFulfilled,onRejected}...]
// 构造函数
constructor(func) {
// pending->fulfilled
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
// pending->rejected
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
// then方法
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new DIYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
// 1.处理返回Promise
if (x instanceof DIYPromise) {
// console.log('DIYPromise实例')
// 2. 调用then方法
// x.then(res => console.log(res), err => console.log(err))
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
})
}
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
}
}
手写Promise-链式编程-fulfilled状态-返回Promise
onFulfilled
的执行结果是否为DIYPromise
实例then
方法,获取兑现和拒绝的原因并通过resolve
和reject
传递即可then
方法的回调函数中返回的Promise
实例报错p2
const p = new DIYPromise((resolve, reject) => {
resolve(1)
})
const p2 = p.then(res => {
return p2
})
p2.then(
res => { },
err => console.log('err:', err))
// 执行异步任务
function runAsynctask(callback) {
if (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 = 'itheima666'
} else {
setTimeout(callback, 0)
}
}
/**
* 链式编程-处理Promise(fulfilled状态)
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 状态
state = PENDING
// 原因
result = undefined
// 回调函数数组
#handlers = [] // [{onFulfilled,onRejected}...]
// 构造函数
constructor(func) {
// pending->fulfilled
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
// pending->rejected
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
// then方法
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new DIYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
// 1. 处理重复引用
if (x === p2) {
// console.log('返回了p2')
// 2. 抛出错误 Chaining cycle detected for promise #
throw new TypeError('Chaining cycle detected for promise #' )
}
if (x instanceof DIYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
})
}
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
}
}
手写Promise-链式编程-fulfilled状态-重复引用
onFulfilled
函数的返回值是否和then
方法内部返回的DIYPromise
相同new TypeError('Chaining cycle detected for promise #')
then
的第二个回调函数,执行reject
时的链式编程const p = new DIYPromise((resolve, reject) => {
reject(1)
})
const p2 = p.then(undefined, err => {
throw 'error'
// return p2
// return 2
// return new DIYPromise((resolve, reject) => {
// resolve('DIYPromise-2')
// })
})
p2.then(res => {
console.log('p2-res:', res)
}, err => {
console.log('p2-err:', err)
})
onRejected
的异常onRejected
的返回值fulfilled
状态中的处理逻辑抽取为函数resolvePromise
并复用fulfilled
和rejected
状态中调用函数resolvePromise
// 执行异步任务
function runAsynctask(callback) {
if (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 = 'itheima666'
} else {
setTimeout(callback, 0)
}
}
/**
* 链式编程-处理Promise(fulfilled状态)
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 状态
state = PENDING
// 原因
result = undefined
// 回调函数数组
#handlers = [] // [{onFulfilled,onRejected}...]
// 构造函数
constructor(func) {
// pending->fulfilled
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
// pending->rejected
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
// then方法
// 1. 处理异常
// 2. 获取返回值
// 3. 抽取函数
// 4. 调用函数
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new HMPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
// 4. 调用函数
resolvePromise(p2, x, resolve, reject)
// if (x === p2) {
// throw new TypeError('Chaining cycle detected for promise #')
// }
// if (x instanceof DIYPromise) {
// x.then(res => resolve(res), err => reject(err))
// } else {
// resolve(x)
// }
} catch (error) {
reject(error)
}
})
}
else if (this.state === REJECTED) {
runAsynctask(() => {
// 1. 处理异常
try {
// 2. 获取返回值
const x = onRejected(this.result)
// console.log('x:', x)
// 4. 调用函数
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
onFulfilled(this.result)
})
}, onRejected: () => {
runAsynctask(() => {
onRejected(this.result)
})
}
})
}
})
return p2
}
}
// 3. 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #' )
}
if (x instanceof DIYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
手写Promise-链式编程-rejected状态
onRejected
可能出现的异常,如果出现通过reject
传递onRejected
函数的执行结果fulfilled
状态时的处理逻辑抽取为函数,rejected
状态时调用函数复用逻辑const p = new DIYPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
const p2 = p.then(res => {
throw 'error'
// return p2
// return 2
// return new HMPromise((resolve, reject) => {
// resolve('resolve-2')
// // reject('reject-2')
// })
})
p2.then(res => {
console.log('p2-res:', res)
}, err => {
console.log('p2-err:', err)
})
pending
状态时推入回调函数数组时增加try-catch
resolvePromise
// 执行异步任务
function runAsynctask(callback) {
if (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 = 'itheima666'
} else {
setTimeout(callback, 0)
}
}
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #' )
}
if (x instanceof DIYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
/**
* 链式编程-处理Promise(fulfilled状态)
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 状态
state = PENDING
// 原因
result = undefined
// 回调函数数组
#handlers = [] // [{onFulfilled,onRejected}...]
// 构造函数
constructor(func) {
// pending->fulfilled
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
// pending->rejected
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
// then方法
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new DIYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
// 1. 处理异常
try {
// 2.获取返回值
const x = onFulfilled(this.result)
// 3.调用函数
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
// 1. 处理异常
try {
// 2.获取返回值
const x = onRejected(this.result)
// 3.调用函数
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
}
手写Promise-链式编程-pending状态
then
方法中pending
状态时推入数组的函数增加try-catch
捕获异常到目前已经将核心功能全部实现啦,接下来开始实现后续功能
catch
finally
resolve
reject
race
all
allSettled
any
catch
,可以实现如下调用const p = new DIYPromise((resolve, reject) => {
reject('reject-error')
// throw 'throw-error'
})
p.then(res => {
console.log('res:', res)
}).catch(err => {
console.log('err:', err)
})
then(undefined,onRjected)
catch
方法,内部调用then
try-catch
包裹constructor
中的func
捕获异常function runAsynctask(callback) {
if (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 = 'itheima666'
} else {
setTimeout(callback, 0)
}
}
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #' )
}
if (x instanceof DIYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class DIYPromise {
// 状态
state = PENDING
// 原因
result = undefined
// 回调函数数组
#handlers = [] // [{onFulfilled,onRejected}...]
// 构造函数
constructor(func) {
// pending->fulfilled
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
// pending->rejected
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
// 2. 处理异常
try {
func(resolve, reject)
} catch (error) {
// console.log('error:', error)
reject(error)
}
}
// then方法
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new DIYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
/**
* catch方法
* 1. 内部调用then方法
* 2. 处理异常
* */
catch(onRejected) {
// 1. 内部调用then方法
return this.then(undefined, onRejected)
}
}
手写Promise-实例方法catch
catch
方法,接收拒绝的回调函数onRejected
catch
方法的本质是内部调用then
方法undefined
,第二个回调函数传入onRejected
即可finally
的回调函数const p = new DIYPromise((resolve, reject) => {
// resolve('resolve-res')
// reject('reject-error')
// throw 'throw-error'
})
p.then(res => {
console.log('res:', res)
}).catch(err => {
console.log('err:', err)
}).finally(() => {
console.log('finally')
})
then(onFinally,onFinally)
,且不接受任何回调函数finally(onFinally) {
return this.then(onFinally,onFinally)
}
手写Promise-实例方法finally
finally
方法,接收最终执行的回调函数onFinally
finally
方法的本质为内部调用then
方法onFinally
即可finally(onFinally) {
return this.then(onFinally,onFinally)
}
到目前已经将实例方法都实现啦
catch
finally
resolve
reject
race
all
allSettled
any
Promise
对象DIYPromise.resolve(new DIYPromise((resolve, reject) => {
// resolve('resolve')
// reject('reject')
// throw 'error'
})).then(res => {
console.log('res:', res)
}, err => {
console.log('err:', err)
})
DIYPromise.resolve('javascript').then(res => {
console.log(res)
})
resolve
,根据传入的值返回不同的结果即可 static resolve(value) {
// 1. 判断传入值
if (value instanceof DIYPromise) {
// 2.1 Promise直接返回
return value
}
// 2.2 转为Promise并返回(fulfilled状态)
// return new HMPromise((resolve, reject) => {
return new DIYPromise((resolve) => {
resolve(value)
})
}
手写Promise-静态方法resolve
static
关键字添加静态方法resolve
,接收参数value
Promise
实例,直接返回Promise
实例并返回,内部通过resolve(value)
传递value
Promise
对象DIYPromise.reject('error').catch(res => {
console.log(res)
})
rejected
状态的Promise
static reject(value) {
// 1. 返回rejected状态的Promise
// new HMPromise((resolve,reject)=>{
return new DIYPromise((undefined, reject) => {
reject(value)
})
}
手写Promise-静态方法reject
reject
并接收参数value
Promise
实例即可成功/失败
结果const p1 = new DIYPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
const p2 = new DIYPromise((resolve, reject) => {
setTimeout(() => {
reject(2)
}, 1000)
})
DIYPromise.race([p1, p2, 'javascript']).then((res) => {
console.log('res:', res)
}, err => {
console.log('err:', err)
})
Promise
static race(promises) {
// 1. 返回Promise
return new DIYPromise((resolve, reject) => {
// 2. 判断是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
// 3. 等待第一个敲定
promises.forEach(p => {
// p.then
DIYPromise.resolve(p).then(res => { resolve(res) }, err => { reject(err) })
})
})
}
手写Promise-静态方法race
race
接收参数promises
Promise
实例,在返回的Promise
实例中:
reject
传递错误resolve
静态方法等待每一个兑现resolve
传递兑现结果reject
传递拒绝原因const p1 = DIYPromise.resolve(1)
const p2 = new DIYPromise((resolve, reject) => {
setTimeout(() => {
resolve(2)
// reject('error')
}, 1000)
})
const p3 = 3
DIYPromise.all([p1, p2, p3]).then(res => {
console.log('res:', res)
}, err => {
console.log('err:', err)
})
static all(promises) {
// 1. 返回Promise实例
return new DIYPromise((resolve, reject) => {
// 2. 判断是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
// 3. 空数组直接兑现
promises.length === 0 && resolve(promises)
// 4.1 记录结果
const results = []
let count = 0
promises.forEach((p, index) => {
DIYPromise.resolve(p).then(res => {
// results.push 无法保证 结果的顺序和Promise数组的顺序一致
// index 和 Promise实例的索引一致,保证顺序
results[index] = res
// 4.2 判断全部兑现
count++
count === promises.length && resolve(results)
}, err => {
// 5. 处理第一个拒绝
reject(err)
})
})
})
}
手写Promise-静态方法all
all
Promise
实例,在返回的Promise
实例中:
reject
传递错误Promise
数组,通过resolve
静态方法等待结果
Promise
数组的顺序一致reject
传递拒绝原因Promise
数组,当所有对象都已敲定时Promise
对象及以数组形式保存的结果const p1 = DIYPromise.resolve(1)
const p2 = 2
const p3 = new DIYPromise((resolve, reject) => {
setTimeout(() => {
reject(3)
}, 1000)
})
DIYPromise.allSettled([p1, p2, p3]).then(res => {
console.log('res:', res)
}, err => {
console.log('err:', err)
})
Promise
{state:FULFILLED,value:'xxx'}
{state:REJECTED,reason:'xxx'}
static allSettled(promises) {
// 1. 返回Promise
return new DIYPromise((resolve, reject) => {
// 2. 数组判断
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
// 3. 为空直接敲定
promises.length === 0 && resolve(promises)
// 4. 等待全部敲定
// 4.1 记录结果
const results = []
let count = 0
promises.forEach((p, index) => {
DIYPromise.resolve(p).then(res => {
// 4.2 处理兑现{status:'fulfilled',value:''}
results[index] = { status: FULFILLED, value: res }
count++
count === promises.length && resolve(results)
}, err => {
// 4.3 处理拒绝{status:'rejected',reason:''}
results[index] = { status: REJECTED, reason: err }
count++
count === promises.length && resolve(results)
})
})
})
}
手写Promise-静态方法allSettled
做法和all
方法类似,区别是要获取全部敲定的结果(成功/拒绝),以及获取的结果是对象形式
allSettled
Promise
实例,在返回的Promise
实例中:
reject
传递错误Promise
数组,通过resolve
静态方法等待敲定结果{state:FULFILLED,value:'xxx'}
{state:REJECTED,reason:'xxx'}
resolve
传递结果数组Promise
数组,
Promise
对象兑现时,返回一个新的Promise
对象,及对应的结果AggregateError
错误数组const p1 = new DIYPromise((resolve, reject) => {
setTimeout(() => {
reject(1)
}, 2000)
})
const p2 = 2
const p3 = new DIYPromise((resolve, reject) => {
setTimeout(() => {
resolve(3)
// reject(3)
}, 1000)
})
DIYPromise.any([p1, p2, p3]).then(res => {
console.log('res:', res)
}, err => {
console.dir(err)
})
static any(promises) {
// 1. 返回Promise,数组判断
return new DIYPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
// 2. 空数组直接拒绝
promises.length === 0 && reject(new AggregateError(promises, 'All promises were rejected'))
// 3. 等待结果
const errors = []
let count = 0
promises.forEach((p, index) => {
DIYPromise.resolve(p).then(res => {
// 3.1 第一个兑现
resolve(res)
}, err => {
// 3.2 全部拒绝
errors[index] = err
count++
count === promises.length && reject(new AggregateError(errors, 'All promises were rejected'))
})
})
})
}
手写Promise-静态方法any
做法和all
方法也有点类似,区别是获取第一个兑现,或者是全部拒绝
any
Promise
实例,在返回的Promise
实例中:
reject
传递错误Promise
数组,通过resolve
静态方法等待结果
resolve
传递兑现结果Promise
数组一致reject
传递AggregateError
类型的错误,并将拒绝原因数组传递进去即可到目前已经将静态方法都实现啦
catch
finally
resolve
reject
race
all
allSettled
any
接下来咱们来测试一下手写Promise的代码能否通过Promise\A+测试。
Promise\A+是社区推出的规范,其实最早Promise也是社区推出并实现的,旨在规范Promise的实现,里面约定了:
社区提供了promises-aplus-tests用来测试实现的Promise是否符合规范,使用方式为:
1. 提供deferred方法,返回对象{promise,resolve,reject}
1.1 promise: pending状态的promise实例(自己手写的Promise)
1.2 resolve: 以传入的原因兑现promise
1.3 reject: 以传入的原因拒绝promise
// 将我们自己手写的Promise拷贝到一个单独的文件,并在底部加上
module.exports = {
deferred() {
const res = {}
// 自己手写的Promise
res.promise = new DIYPromise((resolve, reject) => {
// 内部将resolve和reject赋值上去
res.resolve = resolve
res.reject = reject
})
return res
}
}
npm init -y
npm i promises-aplus-tests -D
package.json
的scripts
中加入DIYPromise
是文件名,根据实际情况调整自己的文件名即可"test": "promises-aplus-tests DIYPromise"
npm run test
我们目前的写法中,没有考虑所有的边界情况,测试时会在2.3.3开始出错
只需要将resolvePromise
函数替换为如下写法即可:
// 符合Promise\A规范(考虑了各种边界情况)
function resolvePromise(p2, x, resolve, reject) {
// 2.3.3.1 如果p2和x引用同一个对象,通过TypeError作为原因来拒绝pormise
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise');
}
/**
* 2.3.3.2 如果x是一个promise,采用他的状态
* 2.3.3.3.1 如果x是pengding状态,promise必须保持等待状态,直到x被fulfilled或rejected
* 2.3.3.3.2 如果x是fulfilled状态,用相同的原因解决promise
* 2.3.3.3.3 如果x是rejected状态,用相同的原因拒绝promise
* */
if (x instanceof DIYPromise) {
x.then(y => {
resolvePromise(p2, y, resolve, reject)
}, reject);
}
// 2.3.3 如果x是一个对象或者函数
else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
// 2.3.3.1 让then成为x.then
try {
var then = x.then;
} catch (e) {
// 2.3.3.2 如果检索属性x.then抛出了异常e,用e作为原因拒绝promise
return reject(e);
}
/**
* 2.3.3.3 如果then是一个函数,通过call调用他,并且将x作为他的this(参数1)
* 调用then时传入2个回调函数:
* 第一个参数叫做resolvePromise(对应到的参数2)
* 第二个参数叫做rejectPromise(对应到参数3)
* */
if (typeof then === 'function') {
// 2.3.3.3.3 如果 resolvePromise 和 rejectPromise 均被调用,或者同一参数被调用了多次,只采用第一次调用,后续的调用会被忽略(观察called后续的赋值+判断)
let called = false;
try {
then.call(
x,
// 2.3.3.3.1 如果 resolvePromise 以 成功原因 y 为参数被调用,继续执行 resolvePromise
y => {
if (called) return;
called = true;
resolvePromise(p2, y, resolve, reject);
},
// 2.3.3.3.2 如果 rejectPromise 以拒绝原因 r 为参数被调用,用 r 拒绝 promise
r => {
if (called) return;
called = true;
reject(r);
}
)
}
// 2.3.3.3.4 如果调用then抛出异常
catch (e) {
// 2.3.3.3.4.1 如果resolvePromise或rejectPromise已经被调用,忽略它
if (called) return;
called = true;
// 2.3.3.3.4.2 否则以 e 作为拒绝原因 拒绝promise
reject(e);
}
} else {
// 2.3.3.4 如果then不是函数,用 x 作为原因 兑现promise
resolve(x);
}
} else {
// 2.3.4 如果x不是对象或函数,用 x 作为原因 兑现promise
return resolve(x);
}
}
替换完毕之后,再次执行npm run test
,全部测试通过.
手写Promise-Promise\A+测试
Promise
和Promise\A+
规范的关系
Promise\A+
是社区推出的规范,最早Promise也是社区推出并实现的,旨在规范Promise
的实现,里面约定了:
pending
,fulfilled
,rejected
then
方法的详细实现细节早期使用Promise
需要导入第三方库,现在在新式浏览器中已经不需要导入第三方库,因为Promise
是默认开启的。
无论是早期实现Promise的第三方库,还是现在的新式浏览器内置的Promise,都是符合Promise\A+
规范要求的。