• 首页

  • 写作

  • 文章归档

  • 照片

  • 友情链接

  • 旅行

  • 读书

  • 日志

  • 随记

  • 人文历史

  • linux

  • 前端
b l o g
b l o g

admin

lzp

01月
01
js

20 行的可链式调用的 promise

发表于 2025-01-01 • 字数统计 2630 • 被 7 人看爆

源码地址:
https://github.com/qyzhizi/js-logical/blob/main/2024-09-30-promise-demo1/my_promise_20lines.js

代码解释

function Promise(fn) {
  this.cbs = [];
    
  const resolve = (value) => {
    setTimeout(() => {
      this.data = value;
      this.cbs.forEach((cb) => cb(value));
    });
  }
    
  fn(resolve);
}
    
Promise.prototype.then = function (onResolved) {
  return new Promise((resolve) => {
    this.cbs.push(() => {
      const res = onResolved(this.data);
      if (res instanceof Promise) {
        res.then(resolve);
      } else {
        resolve(res);
      }
    });
  });
};

// test
new Promise((resolve) => {
    setTimeout(() => {
      resolve(1);
    }, 500);
  })
    .then((res) => {
      console.log(res);
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(2);
        }, 500);
      });
    })
    .then(console.log);

resolve 闭包

const resolve = (value) => {
  setTimeout(() => {
    this.data = value;
    this.cbs.forEach((cb) => cb(value));
  });
}

this 表示构造函数生成的 Promise 实例的地址,这个函数可以在其他 Promise 实例中被调用,比如在另一个 Promise 实例的 cbs 中等待调用。
setTimeout 是一个异步函数,会被提交到事件循环中。而 then 函数的作用是将一个函数放入到 该造函数生成的 Promise 实例的 this.cbs 中,此时事件循环还未执行提交的函数, 也就是说 then 函数 对 this.cbs 的操作早就执行了,就等事件循环执行了。
回到 resolve 函数,当事件循环开始执行 setTimeout 中的函数时,会设置 this.data 的值,然后执行 then 注册的函数。

resolve 函数的执行 在函数fn(resolve);完成,函数fn(resolve)的调用是一早就在构造函数中完成的,而函数fn是在new Promise(fn)` 时传递的,用户自定义的函数,用户必须在 fn 中调用 resolve, 比如发送完一个请求后,调用 resolve(res) , res 表示请求的结果。

在这段代码中,setTimeout 函数用于模拟异步操作,但是在代码中并没有明确给出具体的延迟时间参数。比如像 setTimeout(() => , 500) 这样明确写了 500 毫秒的就是指定了延迟时间,而如果像 setTimeout(() => ) 这样没有给出具体数字的参数,就意味着延迟时间没有明确指定,具体的延迟时间将由浏览器或运行环境来决定,通常会有一个默认的时间,但这个默认时间不是固定的,可能会因不同的环境而有所差异。

Promise 原型中的then 函数

Promise.prototype.then = function (onResolved) {
  return new Promise((resolve) => {
    this.cbs.push(() => {
      const res = onResolved(this.data);
      if (res instanceof Promise) {
        res.then(resolve);
      } else {
        resolve(res);
      }
    });
  });
};

如上面所说的 then 函数是为了注册新函数到 调用者(promise 实例)的 cbs 列表中,方便在 调用者执行 resolve 时被调用,实现了链式调用重要的一环。 onResolved 也是一个函数,它的作用是对 this.data (调用者.data)的后续处理, 这里的 this.data 需要注意,当调用者(promise 实例)执行 than 函数的时候,此时 this 被绑定为 调用者(promise 实例)的地址, 因为此时 new Promise 所传入的函数 才刚刚被定义,在构造函数执行时还没有被定义,那时应该只是一串代码。
this.cbs.push 的函数 是个箭头函数,先执行 const res = onResolved(this.data); 关键是后面的处理过程,如果 res 是 Promise 实例,那么就执行 res.then(resolve); 否者执行 resolve(res); 这里是个难点不好理解。首先 res 实例 是一个 user promise, 不在主线 promise 上面, res.then(resolve); 表示在另一个 promise 中注册这个 resolve 函数,注意这里的 resolve 是一个主线上即将返回的 promise 的闭包,可以让主线 promise 调用链继续执行的关键,而注册到 另一个 promise 中 cbs 中,是为了等待 另一个 promise 执行完毕后,在继续执行主线上的 resolve。
如果 res 不是 Promise 实例,那么就直接执行 resolve(res); 继续执行主链上的操作。

调用测试

// test
new Promise((resolve) => {
    setTimeout(() => {
      resolve(1);
    }, 500);
  })
    .then((res) => {
      console.log(res);
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(2);
        }, 500);
      });
    })
    .then(console.log);

结果:

-> % node test.js
1
2

主线 promise 起始于 new Promise, 在第一个 then 函数中 返回了一个 user promise, 第二个 then 注册的函数会在 user promise 完成后再执行

参考:
https://juejin.cn/post/6844904094079926286
https://leetcode.cn/circle/discuss/QTeFbj/

分享到:
window10 m40 GPU driver install && Wddm Mode && Driver Version: 536.25
20 行的可链式调用的 promise
  • 文章目录
  • 站点概览
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 · 站点地图