1- Promise 对象的基础模型 (同步,分析执行流程)
- Promise 是一个类,类接收的是一个构造函数,在执行类的时候这个构造函数也会同步执行。
- 构造函数在同步执行的时候,会传递俩个回调函数,分别是成功回调[resolve]、失败回调[reject]。
- 成功回调:回调函数内接收一个参数,可以是一个普通值,也可以是一个 Promise 对象。此阶段暂时只考虑普通值。
- 失败回调:回调函数内接收一个参数,一般为失败原因
- Promise 中有三个状态,分别为 等待[pending]、成功[fulfilled]、失败[rejected]。状态仅支持 pending -> fulfilled 或 pending -> rejected,状态一旦确定就不支持修改了。
- then 方法会接收俩个参数,成功回调[successCallback]函数、失败回调[failCallback]函数。在 then 方法执行时,会依据Promise 的执行状态,执行成功回调或者失败回调。并在执行相对应的回调时,取出相对应的缓存状态值,作为参数传递至回调函数。
// Promise 的三个状态
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败
/**
* 模拟 原生Promise
*
* @class MyPromise
* @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
*/
class MyPromise {
constructor( excutor ) {
excutor(this.resolve, this.reject)
}
// 默认状态为 pending(等待)
status = PENDING
// 缓存状态值
value = undefined // 成功状态 【参数】
reason = undefined // 失败状态 【原因】
/**
* 成功回调
*
* @see 函数使用箭头函数,可以使 this 指向于当前 MyPromise 对象
*/
resolve = (value) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 fulfilled(成功)
this.status = FULFILLED
// 缓存成功回调 传递的值
this.value = value
}
/**
* 失败回调
*/
reject = (reason) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 rejected(失败)
this.status = REJECTED
// 缓存失败回调 传递的原因
this.reason = reason
}
/**
* then 方法
*
* @params {function} successCallback[成功回调]
* @params {function} failCallback[失败回调]
*/
then ( successCallback, failCallback ) {
if (this.status === FULFILLED) successCallback(this.value)
if (this.status === REJECTED) failCallback(this.reason)
}
}
// 测试当前 MyPromise
let promiseTest = new MyPromise((resolve, reject) => {
resolve('成功')
// reject('失败')
})
// 执行 then 方法
promiseTest.then(value => {
console.log(value)
}, reason => {
console.log(reason)
})
2- Promise 对象的异步特性
- 异步特点就是不会阻塞代码执行,待异步结束后才会得到特定的值、特定的函数才会执行。
- 当执行 Promise 中的 then 方法时,Promise 对象的状态为 pending[等待状态时],就断定为异步状态。
- 断定为异步状态时,successCallback[成功回调]、failCallback[失败回调] 需要缓存在 Promise 对象中。
- 在构造函数内的异步方法执行完毕,调用 resolve[成功回调] 、reject[失败回调] 时,前置逻辑处理完毕后,最后执行外部调用 then 方法挂载至 Promise 对象中的 successCallbak[成功回调] 或 failCallback[失败回调]。
// Promise 的三个状态
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败
/**
* 模拟 原生Promise
*
* @class MyPromise
* @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
*/
resolve = (value) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 fulfilled(成功)
this.status = FULFILLED
// 缓存成功回调 传递的值
this.value = value
// 执行成功回调
this.successCallback && this.successCallback(this.value)
}
/**
* 失败回调
*/
reject = (reason) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 rejected(失败)
this.status = REJECTED
// 缓存失败回调 传递的原因
this.reason = reason
// 执行失败回调
this.failCallback && this.failCallback(this.reason)
}
/**
* then 方法
*
* @params {function} successCallback[成功回调]
* @params {function} failCallback[失败回调]
*/
then ( successCallback, failCallback ) {
if (this.status === FULFILLED) successCallback(this.value)
else if (this.status === REJECTED) failCallback(this.reason)
else {
// 缓存成功回调
this.successCallback = successCallback
// 缓存失败回调
this.failCallback = failCallback
}
}
}
// 测试当前 MyPromise
let promiseTest = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
// reject('失败')
}, 2000)
})
promiseTest.then((value) => {
console.log('成功回调:', value)
}, (reason) => {
console.log('失败原因:', reason)
})
3- Promise 支持多次调用的特性实现
- 创建 Promise 方法是可以被多次调用的,在调用后每个 then 方法都应该被正确执行。
- 改造缓存回调函数的容器为数组,每次执行 then 方法后,successCallback[成功回调]、failCallback[失败回调] 都应进入对应的缓存栈。
- 在构造函数内调用 resolve[成功回调] 、reject[失败回调] 时,循环执行缓存的回调函数,并在回调函数内传入当前 Promise 的成功数据,或失败原因。
// Promise 的三个状态
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败
/**
* 模拟 原生Promise
*
* @class MyPromise
* @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
*/
class MyPromise {
constructor(excutor) {
excutor(this.resolve, this.reject)
}
// 默认状态为 pending(等待)
status = PENDING
// 缓存状态值
value = undefined // 成功状态 【参数】
reason = undefined // 失败状态 【原因】
// 缓存回调函数
successCallback = [] // 成功回调
failCallback = [] // 失败回调
/**
* 成功回调
*
* @see 函数使用箭头函数,可以使 this 指向于当前 MyPromise 对象
*/
resolve = (value) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 fulfilled(成功)
this.status = FULFILLED
// 缓存成功回调 传递的值
this.value = value
// 执行成功回调
while (this.successCallback.length) this.successCallback.shift()(this.value)
}
/**
* 失败回调
*/
reject = (reason) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 rejected(失败)
this.status = REJECTED
// 缓存失败回调 传递的原因
this.reason = reason
// 执行失败回调
while (this.failCallback.length) this.failCallback.shift()(this.reason)
}
/**
* then 方法
*
* @params {function} successCallback[成功回调]
* @params {function} failCallback[失败回调]
*/
then(successCallback, failCallback) {
if (this.status === FULFILLED) successCallback(this.value)
else if (this.status === REJECTED) failCallback(this.reason)
else {
// 缓存成功回调
this.successCallback.push(successCallback)
// 缓存失败回调
this.failCallback.push(failCallback)
}
}
}
// 测试当前 MyPromise
let promiseTest = (status, num) => {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
if (status) resolve(`成功:${num}`)
else reject(`失败:${num}`)
}, 2000)
})
}
promiseTest(true, 1).then((value) => {
console.log('成功回调:', value)
}, (reason) => {
console.log('失败原因:', reason)
})
promiseTest(false, 2).then((value) => {
console.log('成功回调:', value)
}, (reason) => {
console.log('失败原因:', reason)
})
promiseTest(true, 3).then((value) => {
console.log('成功回调:', value)
}, (reason) => {
console.log('失败原因:', reason)
})
4- Promise 链式调用的特性实现
- 链式调用过程中,then 方法的 successCallback[成功回调]、failCallback[失败回调],是可选项。如果为空,则直接返回上一个 Promise 对象的返回值。
- Promise 对象是支持链式调用的,在执行 then 方法的时候,最终会返回一个新的 Promise 对象。
- 返回的对象,不支持返回当前调用的 Promise 对象。
- 返回的对象如果是对象,则获取 promise 的返回值,依据返回值调用 resolve、reject。
- 返回值是普通值则,调用 resolve 方法。
// Promise 的三个状态
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败
/**
* 模拟 原生Promise
*
* @class MyPromise
* @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
*/
class MyPromise {
constructor(excutor) {
try {
excutor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
// 默认状态为 pending(等待)
status = PENDING
// 缓存状态值
value = undefined // 成功状态 【参数】
reason = undefined // 失败状态 【原因】
// 缓存回调函数
successCallback = [] // 成功回调
failCallback = [] // 失败回调
/**
* 成功回调
*
* @see 函数使用箭头函数,可以使 this 指向于当前 MyPromise 对象
*/
resolve = (value) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 fulfilled(成功)
this.status = FULFILLED
// 缓存成功回调 传递的值
this.value = value
// 执行成功回调
while (this.successCallback.length) this.successCallback.shift()()
}
/**
* 失败回调
*/
reject = (reason) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 rejected(失败)
this.status = REJECTED
// 缓存失败回调 传递的原因
this.reason = reason
// 执行失败回调
while (this.failCallback.length) this.failCallback.shift()()
}
/**
* then 方法
*
* @params {function} successCallback[成功回调]
* @params {function} failCallback[失败回调]
*/
then(successCallback, failCallback) {
// 回调参数可以为空
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : reason => { throw reason }
const promiseNext = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 当前代码块改变为异步状态,获取到 promiseNext 对象
setTimeout(() => {
try {
// 获取到回调结果
let successNext = successCallback(this.value)
// 执行返回逻辑
resolvePromise(promiseNext, successNext, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
// 获取到回调结果
let failNext = failCallback(this.reason)
// 执行返回逻辑
resolvePromise(promiseNext, failNext, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else {
// 缓存成功回调
this.successCallback.push(() => {
setTimeout(() => {
try {
// 获取到回调结果
let successNext = successCallback(this.value)
// 执行返回逻辑
resolvePromise(promiseNext, successNext, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
// 缓存失败回调
this.failCallback.push(() => {
setTimeout(() => {
try {
// 获取到回调结果
let failNext = failCallback(this.reason)
// 执行返回逻辑
resolvePromise(promiseNext, failNext, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
})
// 链式调用,返回新的Promise
return promiseNext
}
}
// 链式调用处理回调函数
function resolvePromise(promise, next, resolve, reject) {
// 禁止返回当前 Promise
if (promise === next) return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
// 判断当前返值状态
if (next instanceof MyPromise) next.then(resolve, reject) // 如果 返回值为 Promise 对象,则获取到返回值,并调用 resolve、reject 方法传递
else resolve(next) // 如果是普通值,则直接调用 resolve 方法
}
// 测试当前 MyPromise
let promiseTest = (status, num) => {
return new MyPromise((resolve, reject) => {
// setTimeout(() => {
if (status) resolve(`成功:${num}`)
else reject(`失败:${num}`)
// }, 2000)
})
}
// 链式调用
promiseTest(true, 1).then((value) => {
console.log('成功回调:', value)
throw Error(value.replace(/成功/, '失败').replace(/[0-9]/g, 2))
}, (reason) => {
console.log('失败原因:', reason)
}).then((value) => {
console.log('成功回调:', value)
return value.replace(/[0-9]/g, 3)
}, (reason) => {
console.log('失败原因:', reason)
return (reason && reason.message || '失败:3').replace(/失败/, '失败 -> 成功').replace(/[0-9]/g, '2 -> 3')
}).then((value) => {
console.log('成功回调:', value)
return value.replace(/[0-9]/g, 4)
}, (reason) => {
console.log('失败原因:', reason)
})
// 参数可选
promiseTest(true, 100).then().then().then((value) => console.log('value', value))
promiseTest(false, -100).then().then().then((value) => console.log(value), (reason) => console.log('reason', reason))
5- Promise 中的 all、resolve、finally、catch 方法
-
Promise 中的 all 方法
- all 方法是一 Promise 的静态方法,可以直接调用。
- 接收的参数为数组,数组中可以有普通值、同步方法、异步方法。
- 调用 all 方法后,会依次按顺序执行形参中的数组包含的值或方法。每个值或执行方法后,获取到的结果应按形参中的顺序缓存。
- all 方法最终的返回值是一个 Promise 对象。如果形参中的每个方法都得以正确执行,没有异常则调用 Promise 对象中的 resolve 方法,把最终结果缓存至返回的 Promise 对象中。如果有异常则把异常的原因,则调用 Promise 对象中的 reject 方法,缓存失败原因。
- 执行 then 方法就可以获取到,all 顺利完整执行的结果,或某一个状态失败的原因。
-
Promise 中的 resolve 方法
- resolve 方法也是一个 Promise 的静态方法,可以直接调用。
- resolve 方法接收一个参数,这个参数可以是普通值,也可以是异步方法。
- 如果接收到的值是普通值,则包装为 Promise 方法后,返回这个 Promise 方法。
- 如果接收到的值是异步方法,则直接返回这个方法。
-
Promise 中的 finally 方法
- finally 方法在 Promise 对象执行后,无论结果是 fulfilled 或 rejected,都会被执行。
- finally 返回值应为一个 Promise 对象,并且继承当前 Promise 对象的状态。
- finally 对象由于无法知道 Promise 的状态,所以回调函数函数不接收任何参数,仅用于无论 Promise 对象何种状态,都要执行的情况。
-
Promise 中的 catch 方法
- catch 方法会捕获 Promise 的失败状态。
- catch 方法内部为调用 then 方法,第一个参数,成功状态为空。
6- 完整的 Promise 对象
// Promise 的三个状态
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败
/**
* 模拟 原生Promise
*
* @class MyPromise
* @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
*/
class MyPromise {
constructor(excutor) {
try {
excutor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
// 默认状态为 pending(等待)
status = PENDING
// 缓存状态值
value = undefined // 成功状态 【参数】
reason = undefined // 失败状态 【原因】
// 缓存回调函数
successCallback = [] // 成功回调
failCallback = [] // 失败回调
/**
* 成功回调
*
* @see 函数使用箭头函数,可以使 this 指向于当前 MyPromise 对象
*/
resolve = (value) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 fulfilled(成功)
this.status = FULFILLED
// 缓存成功回调 传递的值
this.value = value
// 执行成功回调
while (this.successCallback.length) this.successCallback.shift()()
}
/**
* 失败回调
*/
reject = (reason) => {
// 状态一旦确定不支持更改,return 出函数
if (this.status !== PENDING) return
// 更改状态为 rejected(失败)
this.status = REJECTED
// 缓存失败回调 传递的原因
this.reason = reason
// 执行失败回调
while (this.failCallback.length) this.failCallback.shift()()
}
/**
* then 方法
*
* @params {function} successCallback[成功回调]
* @params {function} failCallback[失败回调]
*/
then(successCallback, failCallback) {
// 回调参数可以为空
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : reason => { throw reason }
const promiseNext = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 当前代码块改变为异步状态,获取到 promiseNext 对象
setTimeout(() => {
try {
// 获取到回调结果
let successNext = successCallback(this.value)
// 执行返回逻辑
resolvePromise(promiseNext, successNext, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
// 获取到回调结果
let failNext = failCallback(this.reason)
// 执行返回逻辑
resolvePromise(promiseNext, failNext, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else {
// 缓存成功回调
this.successCallback.push(() => {
setTimeout(() => {
try {
// 获取到回调结果
let successNext = successCallback(this.value)
// 执行返回逻辑
resolvePromise(promiseNext, successNext, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
// 缓存失败回调
this.failCallback.push(() => {
setTimeout(() => {
try {
// 获取到回调结果
let failNext = failCallback(this.reason)
// 执行返回逻辑
resolvePromise(promiseNext, failNext, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
})
// 链式调用,返回新的Promise
return promiseNext
}
/**
* Promise 对象的 finally 方法
*/
finally(callback) {
// 调用 then 方法,获取 Promise 的状态,并返回
return this.then(
// 传递成功值,并把 回调函数包装为 Promise 对象 返回
(value) => MyPromise.resolve(callback()).then(() => value),
// 传递失败原因,并把 回调函数包装为 Promise 对象 返回
(reason) => MyPromise.resolve(callback().then(() => { throw reason })
))
}
/**
* Promise 对象的 then 方法
*/
catch(callback) {
return this.then(undefined, callback)
}
/**
* Promise 对象的 all 方法
*/
static all(array) {
// 缓存最终结果
let result = []
// 缓存结果的
let count = 0
// 返回 Promise 对象
return new MyPromise((resolve, reject) => {
function addData(key, value) {
// 按下标缓存最终值
result[key] = value
// 缓存值的次数
count++
// 缓存值的次数,等于 all 形参的长度,则代表所有方法或值都缓存至结果
if (count === array.length) resolve(result)
}
// 循环依次执行
for (let i = 0; i < array.length; i++) {
// 获取当前执行
let current = array[i]
// 异步方法处理
if (current instanceof MyPromise) {
current.then(value => addData(i, value), reason => resolve(reason))
} else { // 普通值处理
addData(i, current)
}
}
})
}
/**
* Promise 对象的 resolve 方法
*/
static resolve(value) {
if (value instanceof MyPromise) return value // Promise 对象则直接返回
else return new MyPromise(resolve => resolve(value)) // 普通值,则包装为异步方法
}
}
// 链式调用处理回调函数
function resolvePromise(promise, next, resolve, reject) {
// 禁止返回当前 Promise
if (promise === next) return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
// 判断当前返值状态
if (next instanceof MyPromise) next.then(resolve, reject) // 如果 返回值为 Promise 对象,则获取到返回值,并调用 resolve、reject 方法传递
else resolve(next) // 如果是普通值,则直接调用 resolve 方法
}