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

yizhihongxing

让我们来详细讲解“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日

相关文章

  • js变形金刚文字特效代码分享

    让我们来详细讲解如何实现“js变形金刚文字特效”这个效果。 一、效果介绍 “js变形金刚文字特效”是一种在文字上添加动态效果的编程技巧,使文字可以变化、旋转、缩放等等,呈现出类似于变形金刚的效果。该效果可以用于网页设计、广告宣传等多种场合,让页面更加生动有趣。 下面我们将详细介绍如何使用JavaScript代码实现这个特效。 二、实现步骤 1. 创建HTML…

    JavaScript 2023年6月11日
    00
  • HTML5实现无刷新修改URL的方法

    下面是详细的HTML5实现无刷新修改URL的方法的攻略: 1. 使用HTML5 History API HTML5 History API 可以让我们在不刷新页面的情况下更新 URL 地址。使用方式如下: 1.1 修改URL window.history.pushState(state, title, url); 其中: state: 存储当前状态的 Jav…

    JavaScript 2023年6月11日
    00
  • 解析ajaxFileUpload 异步上传文件简单使用

    解析ajaxFileUpload 异步上传文件简单使用攻略 异步上传文件简介 在传统的表单提交中,如果需要上传文件,则需要重新加载整个页面,用户体验并不好,而且上传大文件还会影响页面的响应速度。而异步上传则是采用ajax技术,实现上传文件的同时不刷新整个页面,从而提升用户体验。 ajaxFileUpload 简介 在实现异步上传功能的过程中,ajaxFile…

    JavaScript 2023年6月11日
    00
  • 详解动画插件wow.js的使用方法

    详解动画插件 wow.js 的使用方法 简介 Wow.js 是一款轻量级的 JavaScript 库,可以在网页滚动时为网页元素添加动画效果。这个库的优点是易于集成,使用简单,而且具有可自定义的选项。 安装 Wow.js 依赖于 Animate.css 库,所以它需要先引入 Animate.css。通过 CDN 或者下载到本地都可以。 然后,下载或者通过 C…

    JavaScript 2023年6月10日
    00
  • CSS对Web页面载入效率的影响分析总结

    CSS对Web页面载入效率的影响分析总结 CSS样式表对Web页面的载入效率有着重要的影响,不合理使用会导致页面的加载速度过慢,影响用户访问体验。因此,优化CSS样式表的使用对Web页面性能优化至关重要。下面将从以下几个方面对CSS对Web页面载入效率的影响进行总结。 CSS文件大小的影响 CSS文件大小是影响Web页面载入效率的主要因素之一。较大的CSS文…

    JavaScript 2023年6月10日
    00
  • 深入理解vue3中的reactive()

    当谈到Vue的响应式系统时,有一个重要的函数:reactive()。在Vue3中,reactive()是我们创建响应式对象的首选方法。 1. reactive()函数的作用 reactive()函数可将一个普通JavaScript对象转换为响应式对象,从而使对象的属性变为可观察和自动更新的。这意味着,当响应式对象的某个属性发生变化时,Vue会自动使用新的值重…

    JavaScript 2023年6月10日
    00
  • jquery点击缩略图切换视频播放特效代码分享

    下面是详细讲解”jquery点击缩略图切换视频播放特效代码分享”的完整攻略: 1.需求概述 我们现在需要实现一个点击缩略图切换视频播放的特效,这里有两个核心需求: 点击不同的视频缩略图,展示不同的视频。 点击缩略图切换视频时需要加入过渡效果,让页面更加平滑流畅。 2.实现思路 实现一个点击缩略图切换视频的效果,首先需要用到jQuery库来实现相关的操作。 定…

    JavaScript 2023年6月11日
    00
  • Javascript 是你的高阶函数(高级应用)

    Javascript 是你的高阶函数(高级应用) 在Javascript中,函数是一等公民,这意味着函数可以像变量一样被存储、传递和操作。高阶函数是基于这个概念,是指可以接受函数作为参数并/或返回函数的函数。 传递函数作为参数 以下是一个例子,演示如何将函数作为参数传递: function greet(name, callback) { console.lo…

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