• 首页

  • 写作

  • 文章归档

  • 照片

  • 友情链接

  • 旅行

  • 读书

  • 日志

  • 随记

  • 人文历史

  • linux

  • 前端
b l o g
b l o g

admin

lzp

01月
01
js

手写 Promise

发表于 2025-01-01 • 字数统计 4118 • 被 4 人看爆

手写 Promise

有问题的代码:

function myPromise(callback) {
    // 保存 Promise 的状态和结果
    let state = 'pending';
    let result = undefined;
  
    // 定义 resolve 函数
    function resolve(value) {
      // 状态只能从 pending 转变为 fulfilled
      if (state === 'pending') {
        state = 'fulfilled';
        result = value;
      }
    }
  
    // 定义 reject 函数
    function reject(reason) {
      // 状态只能从 pending 转变为 rejected
      if (state === 'pending') {
        state = 'rejected';
        result = reason;
      }
    }
  
    // 执行传入的回调函数
    try {
      callback(resolve, reject);
    } catch (error) {
      // 如果回调函数抛出异常,将 Promise 的状态设置为 rejected
      reject(error);
    }
  
    // 返回一个具有 then 方法的对象
    return {
      then: function (onFulfilled, onRejected) {
        // 根据 Promise 的状态调用相应的回调函数
        if (state === 'fulfilled') {
          onFulfilled(result);
        } else if (state === 'rejected') {
          onRejected(result);
        }
      },
    };
  }
  
  // 使用手写的 Promise
  const promise = myPromise(function (resolve, reject) {
    // 模拟异步操作
    setTimeout(function () {
      const randomNumber = Math.random();
      if (randomNumber > 0.5) {
        resolve(randomNumber);
      } else {
        reject('Error: Random number is less than 0.5');
      }
    }, 10);
  });
  
  // 使用 then 方法处理 Promise 的结果

  promise.then(
    function (value) {
      console.log('Fulfilled:', value);
    },
    function (reason) {
      console.log('Rejected:', reason);
    }
  );

这段代码有什么问题?

这段代码实现了一个简单的 Promise 模拟,但存在一些问题,特别是在处理异步操作和状态管理方面。以下是主要问题及其解决方案:
主要问题

状态管理不完整
当前的 then 方法只在 Promise 状态已经确定后(fulfilled 或 rejected)被调用。如果在调用 then 时,Promise 仍处于 pending 状态,回调函数将不会被执行。这会导致用户无法在 Promise 完成后获取结果。
链式调用支持缺失
当前实现的 then 方法不支持链式调用。每次调用 then 都应该返回一个新的 Promise,以便可以继续调用后续的 then。
异步执行中的状态更新
当 Promise 处于 pending 状态时,应该将传入的回调函数(onFulfilled 和 onRejected)保存起来,并在状态改变时执行它们。

改进后的代码,还是有问题,看不懂

以下是修正过的问题并添加了链式调用支持的代码示例:

完整代码:

function myPromise(callback) {
    // 保存 Promise 的状态和结果
    let state = 'pending';
    let result = undefined;
    const onFulfilledCallbacks = [];
    const onRejectedCallbacks = [];

    // 定义 resolve 函数
    function resolve(value) {
        if (state === 'pending') {
            state = 'fulfilled';
            result = value;
            // 执行所有 onFulfilled 回调
            onFulfilledCallbacks.forEach(cb => cb(result));
        }
    }

    // 定义 reject 函数
    function reject(reason) {
        if (state === 'pending') {
            state = 'rejected';
            result = reason;
            // 执行所有 onRejected 回调
            onRejectedCallbacks.forEach(cb => cb(result));
        }
    }

    // 执行传入的回调函数
    try {
        callback(resolve, reject);
    } catch (error) {
        reject(error);
    }

    // 返回一个具有 then 方法的对象
    return {
        then: function (onFulfilled, onRejected) {
            return myPromise((resolve, reject) => {
                // 根据 Promise 的状态调用相应的回调函数
                if (state === 'fulfilled') {
                    onFulfilled ? resolve(onFulfilled(result)) : resolve(result);
                } else if (state === 'rejected') {
                    onRejected ? reject(onRejected(result)) : reject(result);
                } else {
                    // 如果还是 pending 状态,保存回调函数
                    onFulfilledCallbacks.push(value => {
                        if (onFulfilled) {
                            resolve(onFulfilled(value));
                        } else {
                            resolve(value);
                        }
                    });
                    onRejectedCallbacks.push(reason => {
                        if (onRejected) {
                            reject(onRejected(reason));
                        } else {
                            reject(reason);
                        }
                    });
                }
            });
        },
    };
}

// 使用手写的 Promise
const promise = myPromise(function (resolve, reject) {
    setTimeout(function () {
        const randomNumber = Math.random();
        if (randomNumber > 0.5) {
            resolve(randomNumber);
        } else {
            reject(`Error: Random number ${randomNumber} is less than 0.5`);
        }
    }, 10);
});

// 使用 then 方法处理 Promise 的结果
promise.then(
    function (value) {
        console.log('Fulfilled:', value);
        return value + 1; // 返回一个新的值以测试链式调用
    },
    function (reason) {
        console.log('Rejected:', reason);
        return reason
    }
).then(
    function (value) { 
        console.log('Chained Fulfilled:', value); 
    },
    function (reason) { 
        console.log('Chained Rejected:', reason); 
    }
);

运行代码

qy@QY [21:36:05] [~/Documents/git_rep/js-logical/2024-09-30-promise-demo1] [main *]
-> % node test6.js
Fulfilled: 0.6364998457900277
Chained Fulfilled: 1.6364998457900277

qy@QY [21:36:06] [~/Documents/git_rep/js-logical/2024-09-30-promise-demo1] [main *]
-> % node test6.js
Rejected: Error: Random number 0.27835075383137275 is less than 0.5
Chained Rejected: Error: Random number 0.27835075383137275 is less than 0.5

改进点总结

状态管理:通过使用数组存储 onFulfilled 和 onRejected 回调函数,在状态改变时执行它们。
链式调用:每次调用 then 返回一个新的 Promise,以支持链式调用。
回调执行:确保在状态改变时能够正确执行相应的回调。
这样修改后的代码更符合 Promise 的规范,能够更好地处理异步操作,并支持链式调用。

参考:

https://www.perplexity.ai/search/function-mypromise-callback-ba-MkWZwC0HR4Cf0zYFHxsfYQ
没有问题的代码,手写一个Promise/A+,完美通过官方872个测试用例

Promise几乎是面试必考点,所以我们不能仅仅会用,还得知道他的底层原理,学习他原理的最好方法就是自己也实现一个Promise。所以本文会自己实现一个遵循Promise/A+规范的Promise。实现之后,我们还要用Promise/A+官方的测试工具来测试下我们的实现是否正确,这个工具总共有872个测试用例,全部通过才算是符合Promise/A+规范,下面是他们的链接:
博客链接:
https://segmentfault.com/a/1190000023157856

本文的完整代码托管在GitHub上: https://github.com/dennis-jiang/Front-End-Knowledges/blob/master/Examples/JavaScript/Promise/MyPromise.js

Promise/A+规范: https://github.com/promises-aplus/promises-spec

Promise/A+测试工具: https://github.com/promises-aplus/promises-tests

分享到:
异步机制 异步IO 事件循环 事件驱动 内核消息通知 信号 中断机制
Mac 开发环境配置
  • 文章目录
  • 站点概览
admin

! lzp

hello

Github Twitter QQ Email Telegram RSS
看爆 Top5
  • 历史与人文 视频链接 189次看爆
  • 2022日志随笔 175次看爆
  • 我的青海湖骑行 164次看爆
  • 读书随笔 124次看爆
  • rs2 设置教程 97次看爆

站点已萌萌哒运行 00 天 00 小时 00 分 00 秒(●'◡'●)ノ♥

Copyright © 2025 admin

由 Halo 强力驱动 · Theme by Sagiri · 站点地图