promise链式调用_三分钟手撕Promise

31c21f772aeaf99a35d503fec43957ea.png

前言

Promise 在前端开发使用中再频繁不过了,一开始出现的初衷是为了解决棘手的回调地狱问题,现在多是用来解决异步同步的场景。一起来尝试一下手撕这道经典的手写面试题【手写一个 proimse】

食用指南

Promise 基本API:reslove reject then
Promise 核心原理:链式调用解决回调地狱
Promise 其他API: race finally
其他手写系列面试题:拉到最底部

Promise基本功能

4afe3c10cd8d049b9b102a5df0336e4b.png

图片引用自廖雪峰

最常见的三个API: reslove reject then
最基本的三个状态:pending 过渡态 fulfilled 完成态 rejected 失败态

先来回忆下常用的Promise调用

const promise = new Promise(function(resolve, reject) {
    // ... some code

    if (/* 异步操作成功 */){
      resolve(value);
    } else {
      reject(error);
    }
  });
promise.then(result => {
    // const res = /*返回的数据*/
})

这里可以拆分为几个步骤

1. promise 是一个构造函数
2. resolve 函数用来接收成功结果, reject 函数用来接收失败结果
3. 执行 reslove / reject 函数时修改当前状态值
4. 将接到到的结果(full, fail)返回到 then 函数

尝试实现

function myPromise(executor) {
  let _this = this;
  _this.$$status = "pending"; // 声明初始状态
  _this.failCallBack = undefined;
  _this.successCallback = undefined;

  executor(resolve.bind(this), reject.bind(this));

  // 2.
  function resolve(opts) {
    // 3.修改状态值
    if (_this.$$status === "pending") {
      _this.$$status = "full";
      _this.successCallback(opts); // 将接收到的成功结果抛到then函数
    }
  }
  // 2.
  function reject() {
    // 3.修改状态值
    if (_this.$$status === "pending") {
      _this.$$status = "fail";
      _this.failCallBack(opts);
    }
  }
}

// 4.拓展then回调函数接收执行结果
myPromise.prototype.then = function (full, fail) {
  this.successCallback = full;
  this.failCallBack = fail;
};

测试代码

new myPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("成功");
  }, 200);
}).then((result) => {
  console.log(result);
});

到这里就完成了Prmoise最基本的功能API,接下来尝试用Promise解决回调地狱。


Promise 主要功能

Promise 出现的最大的意义是解决了回调地狱,而Promise 最终会返回一个新的 promise 对象, 所以接下来继续思考:
  • 如何编写调用.then() 链式调用函数来解决回调地狱的问题?
  • 并且如何等待第一个.then()函数状态值改变后,再执行第二个.then()?
  • 如何调用 Promise 会返回一个新的 promise 对象?

先来回忆下Promise的链式调用

function begin() {
 return new Promise((resolve) => {
 setTimeout((_) => resolve("first"), 2000);
  });
}

begin()
  .then((data) => {
 console.log(data);
 return new Promise((resolve) => {});
  })
  .then((res) => {
 console.log(res);
  });

尝试实现

这里主要拆解为几个步骤:
  1. then 函数返回新的 promise 对象(这也是可以链式调用的主要原因)
  2. 等待第一个回调函数状态发生改变后pending->full,包装第一个 then 方法返回的值为新的 Promise,传递给第二个 then 方法。

先来实行第一步,简单扩展之前写的 then()函数

function myPromise(executor) {
  let _this = this;
  _this.$$status = "pending"; // 声明初始状态
  _this.failCallBack = undefined;
  _this.successCallback = undefined;
  _this.failDefer = undefined;
  _this.successDefer = undefined;
  executor(this.resolve.bind(this), this.reject.bind(this));
}

myPromise.prototype = {
  constructor: this,
  resolve: function (params) {
    // ...
  },
  reject: function (params) {
    //...
  },
  then: function (full, fail) {
    let newMyPromise = new myPromise((_) => {});
    this.successCallback = full; // 接受调用reslove()时传进来的执行函数
    this.failCallback = fail; // 接收调用reject()时传进来的执行函数
    this.successDefer = newMyPromise.resolve.bind(newMyPromise); // 为什么要绑定?继续往下看
    this.failDefer = newMyPromise.reject.bind(newMyPromise);
    // 1. 返回一个新的对象
    return newMyPromise;
  },
};

第一步比较简单,接下来继续第二三个步骤:

function myPromise(executor) {
  // 省略 如上
}

myPromise.prototype = {
  constructor: this,
  resolve: function (params) {
    if (this.$$status === "pending") {
      this.$$status = "success"; // 修改状态

      if (!this.successCallback) return;

      // 存储传进来的结果执行函数
      let result = this.successCallback(params);
      if (result && result instanceof myPromise) {
        // 2. 如果已经存在结果值,将结果传递给下一个then()方法。
        result.then(this.successDefer, this.failDefer);
        return "";
      }
      this.successDefer(result);
    }
  },
  reject: function (params) {
    // 同slove
  },
};
完整代码传送门,最底有测试代码​github.com

到目前为止已经实现了一个包含主要功能的Promise了,手写一个Promise可以更好的理解原理,其他API race all finally 手写可参考。

另外附赠其他 手写面试题系列传送门。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值