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

让我们来详细讲解“JavaScript面试必备技巧之手写一个Promise”的完整攻略。

什么是Promise

Promise 是一种处理异步操作的方式,是 ES6 中新增的 JavaScript 特性。Promise 是异步编程的一种解决方案,用于解决回调地狱问题。

Promise的三种状态

一个 Promise 有三种状态:pending(初始状态)、fulfilled(成功状态)和 rejected(失败状态)。

  • pending:Promise 实例被创建后,处于初始状态,既未成功,也未失败;
  • fulfilled:成功状态,表示 Promise 操作成功完成,将返回相应的结果值,该状态下 Promise 不能变为其它状态;
  • rejected:失败状态,表示 Promise 操作未成功完成,并且返回了相应的原因,该状态下 Promise 不能变为其它状态。

手写Promise

以下是手写一个 Promise 的步骤:

  1. 定义Promise的构造函数
class MyPromise {
    constructor(executor) {
        // executor为自定义函数,有 resolve 和 reject 两个参数
        this.status = 'pending'; // Promise对象的初始状态
        this.value = undefined; // Promise对象的返回值
        this.reason = undefined; // Promise对象的失败原因
        try {
            executor(this.resolve, this.reject);
        } catch (error) {
            this.reject(error);
        }
    }
}
  1. 实现 Promise 的 resolve 和 reject 函数
class MyPromise {
    constructor(executor) {
        // 省略代码

        // resolve函数,将 Promise 状态从 pending 改为 fulfilled,同时返回最终处理结果
        this.resolve = value => {
            if (this.status === 'pending') {
                this.status = 'fulfilled';
                this.value = value;
            }
        }

        // reject函数,将 Promise 状态从 pending 改为 rejected,同时返回失败原因
        this.reject = reason => {
            if (this.status === 'pending') {
                this.status = 'rejected';
                this.reason = reason;
            }
        }
    }
}
  1. 实现 Promise 的 then 方法
class MyPromise {
    constructor(executor) {
        // 省略代码

        // then函数,用于异步调用
        this.then = (onFulfilled, onRejected) => {
            if (this.status === 'fulfilled') {
                onFulfilled(this.value);
            }
            if (this.status === 'rejected') {
                onRejected(this.reason);
            }
        }
    }
}
  1. 完善 Promise 的异常处理机制
class MyPromise {
    constructor(executor) {
        // 省略代码

        // 当Promise产生异常时,将状态改为rejected
        try {
            executor(this.resolve, this.reject);
        } catch (error) {
            this.reject(error);
        }
    }

    // then方法要返回一个新的 Promise 实例,因此需在 then 中创建新的 Promise
    // 用来异步执行 onFulfilled 和 onRejected 函数
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; }
        const promise2 = new MyPromise((resolve, reject) => {
            if (this.status === 'fulfilled') {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(this.value);
                        this.resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            }
            if (this.status === 'rejected') {
                setTimeout(() => {
                    try {
                        const x = onRejected(this.reason);
                        this.resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            }
        });
        return promise2;
    }

    // 添加resolvePromise方法,用于处理then回调函数返回值的情况
    resolvePromise(promise2, x, resolve, reject) {
        if (promise2 === x) {
            return reject(new TypeError('Chaining cycle detected for promise'));
        }
        let called = false;
        if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
            try {
                let then = x.then;
                if (typeof then === 'function') {
                    then.call(x, y => {
                        if (called) return;
                        called = true;
                        this.resolvePromise(promise2, y, resolve, reject);
                    }, r => {
                        if (called) return;
                        called = true;
                        reject(r);
                    })
                } else {
                    resolve(x)
                }
            } catch (error) {
                if (called) return;
                called = true;
                reject(error);
            }
        } else {
            resolve(x);
        }
    }
}

示例说明

示例一

const promise = new MyPromise(resolve => {
    console.log('start promise 1');
    setTimeout(() => resolve('promise 1'), 1000);
})

promise.then(res => {
    console.log(res);
})

console.log('end');

当执行以上示例代码时,会先输出 'start promise 1''end',1秒后输出 'promise 1'。这是因为 promise 对象是异步执行的,而 then 函数就是异步的。执行 promise 对象的构造函数不会阻塞主线程,只有当 promise 对象的相关操作发生时,才会异步执行 then 函数中的回调函数。

示例二

const promise = new MyPromise(resolve => {
    console.log('start promise 2');
    setTimeout(() => {
        resolve('promise 2');
    }, 1000);
}).then(res => {
    console.log(1);
    return res;
}).then(res => {
    console.log(2);
    return res;
}).then(res => {
    console.log(3);
    return res;
});

console.log('end');

当执行以上示例代码时,会先输出 'start promise 2''end',然后等待 1 秒后输出 1,再等待 1 秒后输出 2,最后输出 3。这是因为当一个 promise 对象链式调用多个 then 方法时,每个 then 方法返回一个新的 Promise 对象,用来串联每个回调函数的返回结果,形成一个 promise 链式调用过程。因此在执行 then 方法前,promise 对象并不会停止,而是继续执行,直到 promise 对象完成操作后,才会继续执行 then 中的回调函数。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript面试必备技巧之手写一个Promise - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • javascript如何创建对象

    创建对象在 JavaScript 中是一项重要的任务,以下是常用的四种方式来创建对象: 1. 对象字面量 对象字面量是创建 JavaScript 对象的一种简单方式,可以在代码中直接定义。定义对象字面量时需要使用花括号 {}。在花括号中,可以按照属性名称和对应的值的形式来定义对象的属性,多个属性之间使用逗号分隔。 let person = { name: ‘…

    JavaScript 2023年5月27日
    00
  • 微信小程序 animation API详解及实例代码

    关于“微信小程序 animation API详解及实例代码”的完整攻略,我将从以下几个方面进行详细讲解: 介绍animation API的基本用法 animation API中常用的函数与属性 对animation API进行示例练习,包括动画样式的切换以及动画的时序控制 实例代码演示 1. animation API的基本用法 animation可以实现在…

    JavaScript 2023年6月11日
    00
  • JavaScript+html5 canvas制作的百花齐放效果完整实例

    下面我将为您详细讲解“JavaScript+html5 canvas制作的百花齐放效果完整实例”的完整攻略。 需求分析 首先我们需要明确需求,对于“JavaScript+html5 canvas制作的百花齐放效果完整实例”,我们需要实现什么样的效果呢? 具体而言,我们需要实现以下特点: 在canvas上绘制出多个不同颜色、不同形状的花朵 花朵应该随机飘落、旋…

    JavaScript 2023年6月10日
    00
  • 解析Json字符串的三种方法日常常用

    当你需要从后端获取JSON格式的数据并在前端使用时,你需要解析该JSON字符串,将其转换为JavaScript对象,从而方便你在前端进行数据处理和呈现。下面将介绍三种常用的解析JSON字符串的方法: 1. 手动解析 手动解析JSON是最基本的方法。步骤如下: 使用JSON.parse()将JSON字符串转换为JavaScript对象 访问JavaScript…

    JavaScript 2023年5月27日
    00
  • JavaScript的事件机制详解

    JavaScript的事件机制详解 事件机制是 JavaScript 重要的一部分,它使得 Web 应用得以用户交互和响应。在本文中,我将详细讲解 JavaScript 的事件机制,包括事件模型、事件流以及事件捕获和冒泡。 事件模型 JavaScript 事件模型是一种基于事件触发的编程模型。当用户操作网页中的元素(如按钮、文本输入框等)时,会触发事件,Ja…

    JavaScript 2023年5月28日
    00
  • JS中数组常用的循环遍历你会几种

    JS中数组常用的循环遍历方法主要有五种:for循环、forEach、map、filter和reduce。这些方法可以遍历数组,访问每一个元素,并对它们进行操作。 for循环 for循环是一种基本的JS循环结构,它可以循环遍历数组中的所有元素,并对它们进行操作。 示例: let arr = [1, 2, 3, 4, 5]; for (let i = 0; i …

    JavaScript 2023年5月27日
    00
  • JavaScript门道之标准库

    JavaScript 标准库是指由 ECMAScript 提供的可在 Web 应用程序中直接使用的库。它包含一组全局对象,例如 Object,Array,Date 和 Error,并提供了一组通用的函数,例如 parseInt 和 parseFloat 等。JavaScript 标准库是在 JavaScript 运行时环境中自动加载的,因此不需要额外下载或引…

    JavaScript 2023年5月19日
    00
  • 微信小程序防止多次点击跳转和防止表单组件输入内容多次验证功能(函数防抖)

    微信小程序中,为了提高用户体验,往往需要对一些按钮或表单组件进行防止多次点击或输入内容多次验证,以避免用户重复提交数据或误操作。这时,我们可以使用函数防抖来实现这些效果。 函数防抖是指在一段时间内,多次触发同一事件,只执行一次函数。具体而言,是在延迟时间内,如果再次触发了同一事件,则清空之前的计时器并重新开始计时,直到延迟时间过去后再触发该事件时才会执行真正…

    JavaScript 2023年6月10日
    00
合作推广
合作推广
分享本页
返回顶部