JS怎样写Promise,原理及方法是什么
Admin 2022-08-08 群英技术资讯 871 次浏览
这篇文章给大家介绍了“JS怎样写Promise,原理及方法是什么”的相关知识,讲解详细,步骤过程清晰,有一定的借鉴学习价值,因此分享给大家做个参考,感兴趣的朋友接下来一起跟随小编看看吧。首先我们从使用的角度来分析一下Promise,然后编写一个最简单版本的Promise。
Promise就是一个类,在执行这个类的时候,需要传递一个执行器(回调函数)进去,执行器会立即执行。
Promise中的状态分为三个,分别是:
状态的切换只有两种,分别是:
一旦状态发生改变,就不会再次改变:
根据我们上面的分析,写出如下代码:
MyPromise.js
// 定义所有状态的常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// Promise实质上就是一个类,首先创建一个Promise的类
class MyPromise {
// 实例化Promise时需要一个回调函数,该回调函数立即执行
constructor(executor) {
// 在调用executor需要传递两个回调函数,分别是resolve和reject
executor(this.resolve, this.reject)
}
// Promise 的状态
status = PENDING
// 记录成功与失败的值
value = undefined
reason = undefined
resolve = (value) => {// 这里使用箭头函数是为了使其内部的this指向为该实例化后的对象
// 形参value表示,调用resolve时传递的参数
// 如果当前状态不是pending,就直接跳出该逻辑
if (this.status !== PENDING) return
// 将状态修改为成功
this.status = FULFILLED
// 将传入的值进行保存
this.value = value
}
reject = (reason) => {// 这里使用箭头函数是为了使其内部的this指向为该实例化后的对象
// 形参reason表示,调用reject时传递的失败的原因
// 如果当前状态不是pending,就直接跳出该逻辑
if (this.status !== PENDING) return
// 将状态修改为失败
this.status = REJECTED
// 保存失败的原因
this.reason = reason
}
// then方法的实现
then (onFulfilled, onRejected) {
// 判断当前状态,根据状态调用指定回调
if (this.status === FULFILLED) {
// 将成功的值作为参数返回
onFulfilled(this.value)
} else if (this.status === REJECTED) {
// 将失败的原因作为参数返回
onRejected(this.reason)
}
}
}
// 导出Promise
module.exports = MyPromise
现在我们就来写一段代码验证一下上面的代码
验证resolve:
const MyPromise = require('./myPromise')
let promise = new MyPromise((resolve, reject) => {
resolve('成功')
})
promise.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
/* 输出
成功
*/
验证reject:
const MyPromise = require('./myPromise')
let promise = new MyPromise((resolve, reject) => {
reject('失败')
})
promise.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
/* 输出
失败
*/
验证状态不可变:
const MyPromise = require('./myPromise')
let promise = new MyPromise((resolve, reject) => {
resolve('成功')
reject('失败')
})
promise.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
/* 输出
成功
*/
如果我们的代码中存在异步操作,我们自己写的Promise将毫无用处,
例如下面这段代码:
const MyPromise = require('./myPromise')
let promise = new MyPromise((resolve, reject) => {
setTimeout(resolve, 2000, '成功')
})
promise.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
这段代码2000ms后没有任何输出,为了解决这个问题我们将对自己编写的类进行如下操作:
then方法添加状态为pending时的处理逻辑,这时将传递进来的属性保存到实例上。实现代码如下:
// MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING
value = undefined
reason = undefined
// 存储成功与失败的处理逻辑
onFulfilled = undefined
onRejected = undefined
resolve = (value) => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// 如果将状态修复为成功,调用成功的回调
this.onFulfilled && this.onFulfilled(this.value)
}
reject = (reason) => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// 如果将状态修复为失败,调用失败的回调
this.onRejected && this.onRejected(this.reason)
}
then (onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else {
// 表示既不是成功,也不是失败。这个时候保存传递进来的两个回调
this.onFulfilled = onFulfilled
this.onRejected = onRejected
}
}
}
module.exports = MyPromise
这里的this.onFulfilled && this.onFulfilled(this.value)表示如果该属性存在就调用这个方法。
现在我们重新执行一开始上面那一段代码,2s后会成功输出成功。
Promise实例中存在要给then方法,允许我们在Promise实例中链式调用,每个then方法还会返回一个Promise实例,
如下图所示:

Promise实例方法then是可以多次进行调用,而我们现在自己封装的却执行调用一次,现在根据新需要来重新改写我们的代码,
实现思路如下:
实现代码如下:
// MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING
value = undefined
reason = undefined
// 存储成功与失败的处理逻辑
onFulfilled = []
onRejected = []
resolve = (value) => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// 如果将状态修复为成功,调用成功的回调
while (this.onFulfilled.length) {
// Array.prototype.shift() 用于删除数组第一个元素,并返回
this.onFulfilled.shift()(this.value)
}
}
reject = (reason) => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// 如果将状态修复为失败,调用失败的回调
while (this.onRejected.length) {
// Array.prototype.shift() 用于删除数组第一个元素,并返回
this.onRejected.shift()(this.reason)
}
}
then (onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else {
// 表示既不是成功,也不是失败。这个时候保存传递进来的两个回调
this.onFulfilled.push(onFulfilled)
this.onRejected.push(onRejected)
}
}
}
module.exports = MyPromise
这里我们通过数组的shift()方法,该方法删除数组的第一个元素,并返回,返回的这个值正好是一个回调函数,然后调用该函数即可实现该功能。
想要实现then的链式调用,主要解决两个问题:
MyPormise实例。then的返回值作为下一次的链式调用的参数。这里分为两种情况:
MyPormise实例,此时就需要判断其状态实现代码如下:
// MyPromise.js
/* 省略的代码同上 */
class MyPromise {
/* 省略的代码同上 */
// then方法的实现
then (onFulfilled, onRejected) {
// then 方法返回一个MyPromise实例
return new MyPromise((resolve, reject) => {
// 判断当前状态,根据状态调用指定回调
if (this.status === FULFILLED) {
// 将成功的值作为参数返回
// 保存执行回调函数的结果
const result = onFulfilled(this.value)
// 如果返回的是一个普通的值,直接调用resolve
// 如果是一个MyPromise实例,根据返回的解决来决定是调用resolve,还是reject
resolvePromise(result, resolve, reject)
} else if (this.status === REJECTED) {
// 将失败的原因作为参数返回
onRejected(this.reason)
} else {
// 表示既不是成功,也不是失败。这个时候保存传递进来的两个回调
this.onFulfilled.push(onFulfilled)
this.onRejected.push(onRejected)
}
})
}
}
function resolvePromise (result, resolve, reject) {
// 判断传递的result是不是MyPromise的实例对象
if (result instanceof MyPromise) {
// 说明是MyPromise的实例对象
// 调用.then方法,然后在回调函数中获取到具体的值,然后调用具体的回调
// result.then(value => resolve(value), reason => reject(reason))
// 简写
result.then(resolve, reject)
} else {
resolve(result)
}
}
module.exports = MyPromise
在Promise中,如果then方法返回的是自己的promise对象,则会发生promise的嵌套,这个时候程序会报错,
测试代码如下:
var promise = new Promise((resolve, reject) => {
resolve(100)
})
var p1 = promise.then(value => {
console.log(value)
return p1
})
// 100
// Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
想要解决这个问题其实我们只需要在then方法返回的MyPromise实例对象与then中回调函数返回的值进行比对,如果相同的返回一个reject的MyPromise实例对象,并创建一个TypeError类型的Error。
实现代码如下:
// MyPromise.js
/* 省略的代码同上 */
then (onFulfilled, onRejected) {
// then 方法返回一个MyPromise实例
const promise = new MyPromise((resolve, reject) => {
// 判断当前状态,根据状态调用指定回调
if (this.status === FULFILLED) {
// 这里并不需要延迟执行,而是通过setTimeout将其变成异步函数
// 如果不变成异步的话是在函数内获取不到promise的
setTimeout(() => {
// 将成功的值作为参数返回
// 保存执行回调函数的结果
const result = onFulfilled(this.value)
// 如果返回的是一个普通的值,直接调用resolve
// 如果是一个MyPromise实例,根据返回的解决来决定是调用resolve,还是reject
resolvePromise(promise, result, resolve, reject)
}, 0)
} else if (this.status === REJECTED) {
// 将失败的原因作为参数返回
onRejected(this.reason)
} else {
// 表示既不是成功,也不是失败。这个时候保存传递进来的两个回调
this.onFulfilled.push(onFulfilled)
this.onRejected.push(onRejected)
}
})
return promise
}
}
function resolvePromise (promise, result, resolve, reject) {
// 这里修改一下该函数,如果return的Promise实例对象,也就是传入的promise===result的话,说明在promise中return的是当前promise对象。
if (promise === result) {
// 这里调用reject,并抛出一个Error
// return 是必须的,阻止程序向下执行
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 判断传递的result是不是MyPromise的实例对象
if (result instanceof MyPromise) {
// 说明是MyPromise的实例对象
// 调用.then方法,然后在回调函数中获取到具体的值,然后调用具体的回调
// result.then(value => resolve(value), reason => reject(reason))
// 简写
result.then(resolve, reject)
} else {
resolve(result)
}
}
module.exports = MyPromise
这里then方法中的setTimeout的作用并不是延迟执行,而是为了调用resolvePromise函数时,保证创建的promise存在。
到目前为止我们现实的Promise并没有对异常做任何处理,为了保证代码的健壮性,我们需要对异常做一些处理。
现在我们需要对执行器进行异常捕获,如果发生异常,就将我们的状态修改为rejected。
捕获执行器的错误也比较简单,只需要在构造函数中加入try...catch语句就可以,
实现代码如下:
constructor(executor) {
try {
// 在调用executor需要传递两个回调函数,分别是resolve和reject
executor(this.resolve, this.reject)
} catch (e) {
// 发生异常调用reject
this.reject(e)
}
}
测试代码如下:
const MyPromise = require('./myPromise')
let promise = new MyPromise((resolve, reject) => {
throw new Error('执行器错误')
})
promise.then(value => {
console.log(value);
}, error => {
console.log(error.message);
})
/* 输出
执行器错误
*/
现在我们需要对then中的异常捕获到,并在下一次链式调用中传递到then的第二个函数中,实现的方式也是通过try...catch语句,
示例代码如下:
// then方法的实现
then (onFulfilled, onRejected) {
// then 方法返回一个MyPromise实例
const promise = new MyPromise((resolve, reject) => {
// 判断当前状态,根据状态调用指定回调
if (this.status === FULFILLED) {
// 这里并不需要延迟执行,而是通过setTimeout将其变成异步函数
// 如果不变成异步的话是在函数内获取不到promise的
setTimeout(() => {
try {
// 将成功的值作为参数返回
// 保存执行回调函数的结果
const result = onFulfilled(this.value)
// 如果返回的是一个普通的值,直接调用resolve
// 如果是一个MyPromise实例,根据返回的解决来决定是调用resolve,还是reject
resolvePromise(promise, result, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else if (this.status === REJECTED) {
// 将失败的原因作为参数返回
onRejected(this.reason)
} else {
// 表示既不是成功,也不是失败。这个时候保存传递进来的两个回调
this.onFulfilled.push(onFulfilled)
this.onRejected.push(onRejected)
}
})
return promise
}
测试代码如下:
const MyPromise = require('./myPromise')
let promise = new MyPromise((resolve, reject) => {
resolve('成功')
})
// 第一个then方法中的错误要在第二个then方法中捕获到
promise.then(value => {
console.log('resolve', value)
throw new Error('then的执行过程中遇到异常')
}).then(null, reason => {
console.log(reason.message)
})
/* 输出
resolve 成功
then的执行过程中遇到异常
*/
现在只对成功状态的then进行的链式调用以及错误处理,错误与异步状态未进行处理,其实处理起来也是一样的,
示例代码如下:
// then方法的实现
then (onFulfilled, onRejected) {
// then 方法返回一个MyPromise实例
const promise = new MyPromise((resolve, reject) => {
// 判断当前状态,根据状态调用指定回调
if (this.status === FULFILLED) {
// 这里并不需要延迟执行,而是通过setTimeout将其变成异步函数
// 如果不变成异步的话是在函数内获取不到promise的
setTimeout(() => {
try {
// 将成功的值作为参数返回
// 保存执行回调函数的结果
const result = onFulfilled(this.value)
// 如果返回的是一个普通的值,直接调用resolve
// 如果是一个MyPromise实例,根据返回的解决来决定是调用resolve,还是reject
resolvePromise(promise, result, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else if (this.status === REJECTED) {
// 失败的处理同成功处理,只是调用的回调函数不同
setTimeout(() => {
try {
const result = onRejected(this.reason)
resolvePromise(promise, result, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else {
this.onFulfilled.push((value) => {
setTimeout(() => {
try {
const result = onFulfilled(value)
resolvePromise(promise, result, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
this.onRejected.push((reason) => {
setTimeout(() => {
try {
const result = onRejected(reason)
resolvePromise(promise, result, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
}
})
return promise
}
测试代码如下:
const MyPromise = require('./myPromise')
let promise = new MyPromise((resolve, reject) => {
setTimeout(resolve, 2000, '成功')
})
// 第一个then方法中的错误要在第二个then方法中捕获到
promise.then(value => {
console.log('resolve', value)
throw new Error('then的执行过程中遇到异常')
}).then(null, reason => {
console.log(reason.message)
})
/* 输出
resolve 成功
then的执行过程中遇到异常
*/
Promise中的then方法其实是两个可以可选参数,如果我们不传递任何参数的话,里面的结果是向下传递的,直到捕获为止,
例如下面这段代码:
new Promise((resolve, reject) => {
resolve(100)
})
.then()
.then()
.then()
.then(value => console.log(value))
// 最后一个then输入100
这段代码可以理解为:
new Promise((resolve, reject) => {
resolve(100)
})
.then(value => value)
.then(value => value)
.then(value => value)
.then(value => console.log(value))
所以说我们只需要在没有传递回调函数时,赋值一个默认的回调函数即可。
实现代码如下:
// then方法的实现
then (onFulfilled, onRejected) {
// 如果传递函数,就是用传递的函数,否则指定一个默认值,用于参数传递
onFulfilled = onFulfilled ? onFulfilled : value => value
// 同理
onRejected = onRejected ? onRejected : reason => { throw reason }
// then 方法返回一个MyPromise实例
const promise = new MyPromise((resolve, reject) => {
// 判断当前状态,根据状态调用指定回调
if (this.status === FULFILLED) {...
} else if (this.status === REJECTED) {...
} else {...
}
})
return promise
}
关于all()方法的使用,可以参数Promise.all()。简单的说Promise.all()会将多个Promise实例包装为一个Promise实例,且顺序与调用顺序一致,
示例代码如下:
function p1 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
}
function p2 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2')
}, 0)
})
}
Promise.all(['a', 'b', p1(), p2(), 'c']).then(result => {
console.log(result)
// ["a", "b", "p1", "p2", "c"]
})
在这段代码中,我们的p1的执行是延迟了2s的,这里如果不使用Promise.all()的话最终顺序是与我们调用不同的。
现在我们来分析一下all()的实现思路:
all()方法可以通过类直接调用,所以是一个静态方法all()方法接收一个数组,数组中的值可以是一个普通值,也可以是一个MyPromise的实例对象rejecte,如果是成功话将这个值存入一个数组resolve并将最终的结果数组作为参数返回。实现代码:
/**
* @description: 将多个Promise实例合并为一个Promise实例
* @param {*} array Promise或者普通值
* @returns {Promise}
*/
static all (array) {
// 用于存放最终结果的数组
let result = []
// 用于计算当前已经执行完的实例的数量
let count = 0
// 最后返回的是一个Promise实例
return new MyPromise((resolve, reject) => {
/**
* @description: 将执行完毕的值加入结果数组,并根据实际情况决定是否调用resolve
* @param {*} result 存放结果的数组
* @param {*} index 要加入的索引
* @param {*} value 要加入数组的值
* @param {*} resolve Promise中的resolve
*/
function addResult (result, index, value, resolve) {
// 根据索引值,将结果堆入数组中
result[index] = value
// 执行完毕一个 count+1,如果当前值等于总长度的话说明已经执行结束了,可以直接调用resolve,说明已经成功执行完毕了
if (++count === array.length) {
// 将执行结果返回
resolve(result)
}
}
// 遍历穿入的数组,每个都执行then方法,获取到最终的结果
array.forEach((p, index) => {
// 判断p是不是MyPromise的实例,如果是的话调用then方法,不是直接将值加入数组中
if (p instanceof MyPromise) {
p.then(
// 成功时将结果直接加入数组中
value => {
addResult(result, index, value, resolve)
},
// 如果失败直接返回失败原因
reason => {
reject(reason)
}
)
}
else {
addResult(result, index, p, resolve)
}
})
})
}
关于Promise.resolve()方法的用法可以参考Promise.resolve()与Promise.reject()。
我们实现的思路主要如下:
实现代码如下:
static resolve (value) {
// 如果是MyPromise的实例,就直接返回这个实例
if (value instanceof MyPromise) return value
// 如果不是的话创建一个MyPromise实例,并返回传递的值
return new MyPromise((resolve) => {
resolve(value)
})
}
关于finally方法可参考finally(),实现该方法的实现代码如下:
finally (callback) {
// 如何拿到当前的promise的状态,使用then方法,而且不管怎样都返回callback
// 而且then方法就是返回一个promise对象,那么我们直接返回then方法调用之后的结果即可
// 我们需要在回调之后拿到成功的回调,所以需要把value也return
// 失败的回调也抛出原因
// 如果callback是一个异步的promise对象,我们还需要等待其执行完毕,所以需要用到静态方法resolve
return this.then(value => {
// 把callback调用之后返回的promise传递过去,并且执行promise,且在成功之后返回value
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
// 失败之后调用的then方法,然后把失败的原因返回出去。
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
测试:
function p1 () {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
}
function p2 () {
return new MyPromise((resolve, reject) => {
reject('p2 reject')
})
}
p2().finally(
() => {
console.log('finally p2')
return p1()
}
).then(
value => {
console.log(value)
}, reason => {
console.log(reason)
}
)
// finally p2
// 两秒之后执行p2 reject
关于catch方法可以参考catch(),实现该方法其实非常简单,只需要在内部调用then方法,不传递第一个回调函数即可,
实现代码如下:
catch (callback) {
return this.then(null, failCallback)
}
测试如下:
function p () {
return new MyPromise((resolve, reject) => {
reject(new Error('reject'))
})
}
p()
.then(value => {
console.log(value)
})
.catch(reason => console.log(reason))
// MyPromise.js
// 定义所有状态的常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// Promise实质上就是一个类,首先创建一个Promise的类
class MyPromise {
// 实例化Promise时需要一个回调函数,该回调函数立即执行
constructor(executor) {
try {
// 在调用executor需要传递两个回调函数,分别是resolve和reject
executor(this.resolve, this.reject)
} catch (e) {
// 发生异常调用reject
this.reject(e)
}
}
// Promise 的状态
status = PENDING
// 记录成功与失败的值
value = undefined
reason = undefined
// 存储成功与失败的处理逻辑
onFulfilled = []
onRejected = []
resolve = (value) => {// 这里使用箭头函数是为了使其内部的this指向为该实例化后的对象
// 形参value表示,调用resolve时传递的参数
// 如果当前状态不是pending,就直接跳出该逻辑
if (this.status !== PENDING) return
// 将状态修改为成功
this.status = FULFILLED
// 将传入的值进行保存
this.value = value
// 如果将状态修复为成功,调用成功的回调
// this.onFulfilled && this.onFulfilled(this.value)
while (this.onFulfilled.length) {
// Array.prototype.shift() 用于删除数组第一个元素,并返回
this.onFulfilled.shift()(this.value)
}
}
reject = (reason) => {// 这里使用箭头函数是为了使其内部的this指向为该实例化后的对象
// 形参reason表示,调用reject时传递的失败的原因
// 如果当前状态不是pending,就直接跳出该逻辑
if (this.status !== PENDING) return
// 将状态修改为失败
this.status = REJECTED
// 保存失败的原因
this.reason = reason
// 如果将状态修复为失败,调用失败的回调
// this.onRejected && this.onRejected(this.reason)
while (this.onRejected.length) {
// Array.prototype.shift() 用于删除数组第一个元素,并返回
this.onRejected.shift()(this.reason)
}
}
// then方法的实现
then (onFulfilled, onRejected) {
// 如果传递函数,就是用传递的函数,否则指定一个默认值,用于参数传递
onFulfilled = onFulfilled ? onFulfilled : value => value
// 同理
onRejected = onRejected ? onRejected : reason => { throw reason }
// then 方法返回一个MyPromise实例
const promise = new MyPromise((resolve, reject) => {
// 判断当前状态,根据状态调用指定回调
if (this.status === FULFILLED) {
// 这里并不需要延迟执行,而是通过setTimeout将其变成异步函数
// 如果不变成异步的话是在函数内获取不到promise的
setTimeout(() => {
try {
// 将成功的值作为参数返回
// 保存执行回调函数的结果
const result = onFulfilled(this.value)
// 如果返回的是一个普通的值,直接调用resolve
// 如果是一个MyPromise实例,根据返回的解决来决定是调用resolve,还是reject
resolvePromise(promise, result, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else if (this.status === REJECTED) {
// 失败的处理同成功处理,只是调用的回调函数不同
setTimeout(() => {
try {
const result = onRejected(this.reason)
resolvePromise(promise, result, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else {
// 表示既不是成功,也不是失败。这个时候保存传递进来的两个回调
// this.onFulfilled.push(onFulfilled)
// this.onRejected.push(onRejected)
this.onFulfilled.push((value) => {
setTimeout(() => {
try {
const result = onFulfilled(value)
resolvePromise(promise, result, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
this.onRejected.push((reason) => {
setTimeout(() => {
try {
const result = onRejected(reason)
resolvePromise(promise, result, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
}
})
return promise
}
catch (callback) {
return this.then(null, callback)
}
finally (callback) {
// 如何拿到当前的promise的状态,使用then方法,而且不管怎样都返回callback
// 而且then方法就是返回一个promise对象,那么我们直接返回then方法调用之后的结果即可
// 我们需要在回调之后拿到成功的回调,所以需要把value也return
// 失败的回调也抛出原因
// 如果callback是一个异步的promise对象,我们还需要等待其执行完毕,所以需要用到静态方法resolve
return this.then(value => {
// 把callback调用之后返回的promise传递过去,并且执行promise,且在成功之后返回value
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
// 失败之后调用的then方法,然后把失败的原因返回出去。
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
/**
* @description: 将多个Promise实例合并为一个Promise实例
* @param {*} array Promise或者普通值
* @returns {Promise}
*/
static all (array) {
// 用于存放最终结果的数组
let result = []
// 用于计算当前已经执行完的实例的数量
let count = 0
// 最后返回的是一个Promise实例
return new MyPromise((resolve, reject) => {
/**
* @description: 将执行完毕的值加入结果数组,并根据实际情况决定是否调用resolve
* @param {*} result 存放结果的数组
* @param {*} index 要加入的索引
* @param {*} value 要加入数组的值
* @param {*} resolve Promise中的resolve
*/
function addResult (result, index, value, resolve) {
// 根据索引值,将结果堆入数组中
result[index] = value
// 执行完毕一个 count+1,如果当前值等于总长度的话说明已经执行结束了,可以直接调用resolve,说明已经成功执行完毕了
if (++count === array.length) {
// 将执行结果返回
resolve(result)
}
}
// 遍历穿入的数组,每个都执行then方法,获取到最终的结果
array.forEach((p, index) => {
// 判断p是不是MyPromise的实例,如果是的话调用then方法,不是直接将值加入数组中
if (p instanceof MyPromise) {
p.then(
// 成功时将结果直接加入数组中
value => {
addResult(result, index, value, resolve)
},
// 如果失败直接返回失败原因
reason => {
reject(reason)
}
)
}
else {
addResult(result, index, p, resolve)
}
})
})
}
static resolve (value) {
// 如果是MyPromise的实例,就直接返回这个实例
if (value instanceof MyPromise) return value
// 如果不是的话创建一个MyPromise实例,并返回传递的值
return new MyPromise((resolve) => {
resolve(value)
})
}
}
function resolvePromise (promise, result, resolve, reject) {
// 这里修改一下该函数,如果return的Promise实例对象,也就是传入的promise===result的话,说明在promise中return的是当前promise对象。
if (promise === result) {
// 这里调用reject,并抛出一个Error
// return 是必须的,阻止程序向下执行
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 判断传递的result是不是MyPromise的实例对象
if (result instanceof MyPromise) {
// 说明是MyPromise的实例对象
// 调用.then方法,然后在回调函数中获取到具体的值,然后调用具体的回调
// result.then(value => resolve(value), reason => reject(reason))
// 简写
result.then(resolve, reject)
} else {
resolve(result)
}
}
module.exports = MyPromise
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章主要为大家详细介绍了vue实现树状表格效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
这篇文章主要为大家详细介绍了js实现轮播图自动切换,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
jquery与javascript如何设置或修改a标签href属性呢?非常的简单,例如小编要修改a标签href属性,将跳转网址改成“www.tpyyes.com”,如下: ahref=www.baidu.comid=myId点击进入百度/a 如果是javascript代码,可以这样写: document.getElementById(myId).se
本文主要介绍了浅谈JS数组内置遍历方法有哪些和区别,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
这篇文章主要介绍了uniapp和vue的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008