promise
手写promise --核心功能-->方法-->promise/A+
参考
mdn--promise
.
.
promise中的核心功能
构造函数
/**
* 构造函数
* 1. 定义类
* 2. 添加构造函数
* 3. 定义resolve/reject
* 4. 执行回调函数
*/
class myPromise {
constructor(func) {
const resolve = (result) => {
console.log('resolve 执行: ' + result);
}
const reject = (result) => {
console.log('reject 执行: ' + result);
}
func(resolve, reject)
}
}
// 测试用例
const p = new myPromise((resolve, reject) => {
resolve('success')
// reject('error')
})
.
状态及原因
一个 Promise 必然处于以下几种状态之一:
待定(pending):初始状态,既没有被兑现,也没有被拒绝。
已兑现(fulfilled):意味着操作成功完成。
已拒绝(rejected):意味着操作失败。
一个待定的 Promise 最终状态可以是已兑现并返回一个值,或者是已拒绝并返回一个原因(错误)。当其中任意一种情况发生时,通过 Promise 的 then 方法串联的处理程序将被调用。如果绑定相应处理程序时 Promise 已经兑现或拒绝,这处理程序将被立即调用,因此在异步操作完成和绑定处理程序之间不存在竞态条件。
如果一个 Promise 已经被兑现或拒绝,即不再处于待定状态,那么则称之为已敲定(settled)。即状态不可逆。
.
const PENDING = 'pending'
const FULFILLED = 'fullfilled'
const REJECTED = 'reject'
class myPromise {
// 1. 添加状态
state = PENDING
// 2. 添加原因
result = undefined
constructor(func) {
const resolve = (result) => {
// 3. 调整状态
// 4. 添加原因
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
}
}
const reject = (result) => {
// 3. 调整状态
// 4. 添加原因
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
}
}
func(resolve, reject)
}
}
// 测试用例
const p = new myPromise((resolve, reject) => {
resolve('success')
reject('error')
// 状态已敲定为fulfilled, 即便执行reject也不会改变状态了
})
.
then方法
> 成功和失败回调
onFulfilled
可选
一个在此 Promise 对象被兑现时异步执行的函数。它的返回值将成为 then() 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数:
value
Promise 对象的兑现值。
如果 onFulfilled
不是一个函数,则内部会被替换为一个恒等函数((x) => x)
,它只是简单地将兑现值向前传递。
onRejected
可选
一个在此 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 catch() 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数:
reason
Promise 对象被拒绝的原因。
如果 onRejected
不是一个函数,则内部会被替换为一个抛出器函数((x) => { throw x; })
,它会抛出它收到的拒绝原因。
const PENDING = 'pending'
const FULFILLED = 'fullfilled'
const REJECTED = 'reject'
class myPromise {
state = PENDING
result = undefined
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
}
}
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 }
// 3. 分情况执行回调
if (this.state === FULFILLED) {
onFulfilled(this.result)
} else if (this.state === REJECTED) {
onRejected(this.result)
}
}
}
// 测试用例
const p = new myPromise((resolve, reject) => {
// resolve('success')
reject('error')
})
p.then(res => {
console.log("回调成功: ", res);
}, err => {
console.log("回调失败: ", err);
})
> 异步和多次调用
const PENDING = 'pending'
const FULFILLED = 'fullfilled'
const REJECTED = 'reject'
class myPromise {
state = PENDING
result = undefined
// 1. 定义实例属性, 保存传入的回调函数, 用对象数组来存
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
// 3. 调用成功回调
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
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(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
})
}
}
}
// 测试用例
const p = new myPromise((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);
})
.
异步任务
> 核心api
为了实现异步任务, vue2使用的核心api有: Promise.then、MutationObserver 、 setImmediate 、 setTimeout
这里我们选用: queueMicrotask 、MutationObserver 、 setTimeout
使用 queueMicrotask 注册的回调函数会在当前宏任务的所有同步代码执行完毕后,但在下一个宏任务(如 DOM 更新、渲染等)开始之前执行。
MutationObserver 接口提供了一种异步监视 DOM 变动的能力。当 DOM 发生变化时,MutationObserver 会触发回调函数。
setTimeout 函数用于设置一个定时器,该定时器在指定的延迟时间后执行一个函数或指定的代码片段。
开启异步任务:
// 1. 异步任务 ==> queueMicrotask
console.log(1);
queueMicrotask(() => {
console.log('queueMicrotask');
})
console.log('2');
// 2. 异步任务 ==> MutationObeserver
console.log(1);
// 创建并返回一个新的观察器,它会在触发指定 DOM 事件时,调用指定的回调函数
const mo = new MutationObserver(() => {
console.log('mutationObserver');
})
// 创建
const divDom = document.createElement('div')
// 监听子节点改变
mo.observe(divDom, { childList: true })
// 修改内容触发回调函数
divDom.innerText = 'hehe'
console.log('2');
// 3. 异步任务 ==> setTimeout
console.log(1);
setTimeout(() => {
console.log('setTimeout');
}, 0)
console.log(2);
.
> 函数封装
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
// 3. 使用封装函数
if (this.state === FULFILLED) {
myAsync(() => {
onFulfilled(this.result)
})
} else if (this.state === REJECTED) {
myAsync(() => {
onRejected(this.result)
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
myAsync(() => {
onFulfilled(this.result)
})
},
onRejected: () => {
myAsync(() => {
onRejected(this.result)
})
}
})
}
}
}
// 1. 定义函数
function myAsync(callback) {
// 2. 调用核心api
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const mo = new MutationObserver(callback)
const divDom = document.createElement('div')
mo.observe(divDom, { childList: true })
divDom.innerText = 'hehe'
} else {
setTimeout(callback, 0)
}
}
// 测试用例
console.log('top');
const p = new myPromise((resolve, reject) => {
resolve('success')
reject('error')
})
p.then(res => {
console.log("then: ", res);
}, err => {
console.log("then: ", err);
})
console.log('bottom');
.
.
.
链式编程
由于这些方法返回 Promise,因此它们可以被链式调用。
.
FULFILLED状态下处理返回值和异常
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
// 1. 返回新的promise实例
const p2 = new myPromise((resolve, reject) => {
if (this.state === FULFILLED) {
myAsync(() => {
try {
// 2. 获取返回值
const x = onFulfilled(this.result)
// console.log(x);
// 3. 处理返回值
resolve(x)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
myAsync(() => {
onRejected(this.result)
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
myAsync(() => {
onFulfilled(this.result)
})
},
onRejected: () => {
myAsync(() => {
onRejected(this.result)
})
}
})
}
})
return p2
}
}
// 测试用例
const p = new myPromise((resolve, reject) => {
resolve('1')
// reject('error')
})
p.then(res => {
console.log("p1: ", res);
throw 'throw error'
return 2
}).then(res => {
console.log("p2: ", res)
}, err => {
console.log("p2: ", err);
})
.
.
FULFILLED状态下处理返回promise
myAsync(() => {
try {
const x = onFulfilled(this.result)
// 1. 处理返回的promise
if (x instanceof myPromise) {
// 2. 调用then方法
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
}
// 测试用例
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);
})
.
.
FULFILLED状态下处理重复引用
try {
const x = onFulfilled(this.result)
// 1. 处理重复的引用
if (x === p2) {
// 2. 抛出错误
throw new TypeError('chaining cycle detected for promise #<#Promise>')
}
if (x instanceof myPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
// 测试用例
const p = new myPromise((resolve, reject) => {
resolve(1)
})
const p2 = p.then(res => {
return p2
})
p2.then(
res => { },
err => console.log('err', err)
)
.
.
REJECTED状态
else if (this.state === REJECTED) {
myAsync(() => {
// 1. 处理异常
try {
// 2. 获取返回值
const x = onRejected(this.result)
// 4. 调用函数
resovlePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
// 3. 抽取函数
function resovlePromise(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)
}
}
// 测试用例
const p = new myPromise((resolve, reject) => {
reject(1)
})
const p2 = p.then(undefined, err => {
// throw 'error'
// return p2
// return 2
return new myPromise((resolve, reject) => {
resolve('myPromise-2')
})
})
p2.then(
res => { console.log('p2-res', res); },
err => console.log('p2-err', err)
)
.
.
PENDING状态
else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
myAsync(() => {
try {
const x = onFulfilled(this.result)
resovlePromise(p2,x,resolve,reject)
} catch (error) {
reject(error)
}
})
},
onRejected: () => {
myAsync(() => {
try {
const x = onRejected(this.result)
resovlePromise(p2,x,resolve,reject)
} catch (error) {
reject(error)
}
})
}
})
}
}
// 测试用例
const p = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
const p2 = p.then(res => {
throw 'error'
// return p2
// return 2
// return new myPromise((resolve, reject) => {
// resolve('resolve-2')
// reject('reject-2')
// })
})
p2.then(
res => { console.log('p2-res', res); },
err => console.log('p2-err', err)
)
.
.
.
promise中的实例方法
.catch()方法
Promise.prototype.catch()
将一个拒绝处理回调函数附加到 Promise 上,并返回一个新的 Promise,如果回调被调用,则解决为回调的返回值,如果 Promise 被兑现,解决为其原始兑现值。
Promise
实例的catch()
方法用于注册一个在promise
被拒绝时调用的函数。它会立即返回一个等效的Promise
对象,这可以允许你链式调用其他promise
的方法。此方法是Promise.prototype.then(undefined, onRejected)
的一种简写形式。
Promise.prototype.finally()
将一个处理器附加到 Promise 上,并返回一个新的 Promise,当原始 Promise 被解决时解决。无论 Promise 是否被兑现还是被拒绝,处理器都会在 Promise 敲定时被调用。