我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么使用JavaScript手写一个Promise

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么使用JavaScript手写一个Promise

这篇文章主要介绍“怎么使用JavaScript手写一个Promise”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用JavaScript手写一个Promise”文章能帮助大家解决问题。

    Promise核心原理实现

    首先我们从使用的角度来分析一下Promise,然后编写一个最简单版本的Promise。

    Promise的使用分析

    Promise就是一个类,在执行这个类的时候,需要传递一个执行器(回调函数)进去,执行器会立即执行。

    Promise中的状态分为三个,分别是:

    • pending→等待

    • fulfilled→成功

    • rejected→失败

    状态的切换只有两种,分别是:

    • pending→fulfilled

    • pending→rejected

    一旦状态发生改变,就不会再次改变:

    • 执行器中的两个参数,分别是resolve和reject,其实就是两个回调函数,调用resolve是从pending状态到fulfilled,调用reject是从状态pending到rejected。传递给这两个回调函数的参数会作为成功或失败的值。

    • Promise的实例对象具有一个then方法,该方法接受两个回调函数,分别来处理成功与失败的状态,then方法内部会进行判断,然后根据当前状态确定调用的回调函数。then方法应该是被定义在原型对象中的。

    • then的回调函数中都包含一个值,如果是成功,表示成功后返回的值;如果是失败就表示失败的原因。

    MyPromise的实现

    根据我们上面的分析,写出如下代码:

    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)        }    }}// 导出Promisemodule.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中加入异步操作

    如果我们的代码中存在异步操作,我们自己写的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.jsconst 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后会成功输出成功

    实现then方法的多次调用

    Promise实例中存在要给then方法,允许我们在Promise实例中链式调用,每个then方法还会返回一个Promise实例,

    如下图所示:

    怎么使用JavaScript手写一个Promise

    Promise实例方法then是可以多次进行调用,而我们现在自己封装的却执行调用一次,现在根据新需要来重新改写我们的代码,

    实现思路如下:

    • 定义可以存储多个回调的数组,用于存储多个回调函数。

    • 如果是同步执行的代码,执行后立即知道执行结果,所以可以直接调用回调函数。

    • 如果是异步代码,需要将每次回调函数保存到数组中,然后状态变化时依次调用函数。

    实现代码如下:

    // MyPromise.jsconst 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的链式调用

    想要实现then的链式调用,主要解决两个问题:

    • 返回的是一个新的MyPormise实例。

    • then的返回值作为下一次的链式调用的参数。

    这里分为两种情况:

    • 直接返回一个值,可以直接作为值使用

    • 返回一个新的MyPormise实例,此时就需要判断其状态

    实现代码如下:

    // MyPromise.jsclass 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

    then方法链式调用识别Promise对象自返回

    在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存在。

    捕获错误及 then 链式调用其他状态代码补充

    到目前为止我们现实的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中的异常捕获到,并在下一次链式调用中传递到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)})

    错误与异步状态的链式调用

    现在只对成功状态的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)})

    将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}

    Promise.all方法的实现

    关于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的实例对象

    • return一个新的MyPromise实例对象

    • 遍历数组中的每一个值,判断值得类型,如果是一个普通值得话直接将值存入一个数组;如果是一个MyPromise的实例对象的话,会调用then方法,然后根据执行后的状态,如果失败的话调用新的MyPromise实例对象中的rejecte,如果是成功话将这个值存入一个数组

    • 存入数组时计数,如果存入的数量达到传入的数组长度,说明调用完毕,执行resolve并将最终的结果数组作为参数返回。

    实现代码:

    static all (array) {    // 用于存放最终结果的数组    let result = []    // 用于计算当前已经执行完的实例的数量    let count = 0    // 最后返回的是一个Promise实例    return new MyPromise((resolve, reject) => {                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.resolve()Promise.reject()

    我们实现的思路主要如下:

    • 该方法是一个静态方法

    • 该方法接受的如果是一个值就将该值包装为一个MyPromise的实例对象返回,如果是一个MyPromise的实例对象,调用then方法返回。

    实现代码如下:

    static resolve (value) {    // 如果是MyPromise的实例,就直接返回这个实例    if (value instanceof MyPromise) return value    // 如果不是的话创建一个MyPromise实例,并返回传递的值    return new MyPromise((resolve) => {        resolve(value)    })}

    finally方法的实现

    关于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方法可以参考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 })        })    }        static all (array) {        // 用于存放最终结果的数组        let result = []        // 用于计算当前已经执行完的实例的数量        let count = 0        // 最后返回的是一个Promise实例        return new MyPromise((resolve, reject) => {                        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

    关于“怎么使用JavaScript手写一个Promise”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    怎么使用JavaScript手写一个Promise

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    怎么使用JavaScript手写一个Promise

    这篇文章主要介绍“怎么使用JavaScript手写一个Promise”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用JavaScript手写一个Promise”文章能帮助大家解决问题。Prom
    2023-07-02

    JavaScript怎么实现手写promise

    这篇文章主要介绍了JavaScript怎么实现手写promise的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JavaScript怎么实现手写promise文章都会有所收获,下面我们一起来看看吧。需求我们先来总
    2023-07-06

    JavaScript面试必备技巧之手写一个Promise

    很多同学在面试的时候都会被要求手写一个Promise,那么今天我总结了一些手写Promise的方法,可以跟着我的思路一起来实现一个Promise,让我们的面试更有把握
    2023-02-08

    javascript中的Promise怎么使用

    这篇“javascript中的Promise怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“javascript中的P
    2023-06-30

    使用canvas怎么实现一个手写签名效果

    这期内容当中小编将会给大家带来有关使用canvas怎么实现一个手写签名效果,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。HTML代码:
    2023-06-09

    怎么在JavaScript中使用Promise控制并发请求个数

    这篇文章给大家介绍怎么在JavaScript中使用Promise控制并发请求个数,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。串行:一个异步请求完了之后在进行下一个请求并行:多个异步请求同时进行串行举例:var p =
    2023-06-15

    怎么手写一个Spring Boot Starter

    这篇文章将为大家详细讲解有关怎么手写一个Spring Boot Starter,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。何为 Starter ?想必大家都使用过 SpringBoot,在 Spring
    2023-06-06

    使用JavaScript编写一个2048小游戏

    今天就跟大家聊聊有关使用JavaScript编写一个2048小游戏,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。JavaScript可以做什么1.可以使网页具有交互性,例如响应用户点
    2023-06-07

    怎么使用php写一个网页

    要使用PHP编写一个网页,需要按照以下步骤进行:1. 安装PHP:首先要确保你的电脑上已经安装了PHP。你可以从PHP官方网站(https://www.php.net/downloads.php)下载适合你操作系统的PHP安装包,并按照安装
    2023-08-12

    使用JavaScript编写一个秒表计时器

    本篇文章给大家分享的是有关使用JavaScript编写一个秒表计时器,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。JavaScript是什么JavaScript是一种直译式的脚
    2023-06-07

    使用JavaScript编写一个百度搜索框

    使用JavaScript编写一个百度搜索框?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。实现原理向输入框动态输入时关键词,将当前关键词作为问号参数后面的值,因为要跨域使用百度的
    2023-06-06

    利用JavaScript怎么编写一个换肤功能

    这篇文章给大家介绍利用JavaScript怎么编写一个换肤功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。原理通过点击事件,获取点击的的图片的信息,在HTML背景图片的路径改变css样式