深刻理解Promise系列(一):手把手教你实现Promise(

2017-06-26  本文已影响0人  任无名F

是什么

Promise是一种对异步操作的封装,主流的规范是Promise/A+。
Promise可以使得异步代码层次清晰,便于理解,且更加容易维护。

追求的效果

那么我们的Promise将要实现怎样的效果呢?举个简单的例子如下:

function p1() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(1);
    }, 1000);
  });
}
function p2(value) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(2 + value);
    }, 1000);
  });
}
p1().then(function(res) {
  console.log(res); // 1000ms后输出1
  return Promise.resolve(res); // 显式的return一个Promise对象
}).then(p2).then(function(res) {
  console.log(res); // 再过1000ms后输出3
});

我们手写的Promise最终也可以实现这个效果

最基本的构建

function Promise(fn) {
  let value = null; // 异步函数执行后的结果
  let deferred; // 异步函数执行后,真正要执行的回调函数
  this.then = function(onFulfilled) {
    deferred = onFulfilled;
  }
  function resolve(newValue) {
    value = newValue;
    deferred(value);
  }
  fn(resolve);
}

代码很少,也很容易理解:

改进1

目前的代码只能注册一个回调方法,这显然不符合我们的预期,所以将内部的deferred修改为deferreds数组,相应的执行resolve时,也要遍历deferreds数组依次执行:

function Promise(fn) {
  let value = null;
  let deferreds = [];
  this.then = function(onFulfilled) {
    deferreds.push(onFulfilled);
  }
  function resolve(newValue) {
    value = newValue;
    deferreds.forEach((deferred) => {
      deferred(value);
    });
  }
  fn(resolve);
}

改进2

实现then的链式调用,非常简单:

  this.then = function(onFulfilled) {
    deferreds.push(onFulfilled);
    return this;
  }

这样就可以实现:

p1().then(function(res) {
  // do sth. with res
}).then(function(res) {
  // do sth. else with res
});

延时resolve

目前的Promise有一个bug,假如fn中所包含的是同步代码,则resolve会立即执行,此时then还没有注册回调函数,内部的deferreds为空数组,所以回调函数不会如预期一样执行。
所以,为resolve添加一个延时:

  function resolve(newValue) {
    value = newValue;
    setTimeout(() => {
      deferreds.forEach((deferred) => {
        deferred(value);
      });
    }, 0);
  }

以上保证了resolve于then注册回调函数之后执行。

引入状态

目前还存在一点问题,现在用then注册回调函数的行为都是在异步操作成功之前,一旦异步操作已经成功后,内部resolve已经执行完毕,再用then方法注册回调函数就不会再执行了。
想要解决这个问题,需要引入规范中的三个状态:pending、fulfilled、rejected,它们之间的关系是:


Promise的三种状态

引入状态后的代码:

function Promise(fn) {
  let state = "pending";
  let value = null;
  let deferreds = [];
  this.then = function(onFulfilled) {
    // state若为pending则将onFulfilled加入队列
    if(state === "pending") {
      deferreds.push(onFulfilled);
      return this;
    }
    // state若为fulfilled则立即执行onFulfilled
    onFulfilled(value);
    return this;
  }
  function resolve(newValue) {
    state = "fulfilled"; // 异步操作完成后将state置为fulfilled
    value = newValue;
    setTimeout(() => {
      deferreds.forEach((deferred) => {
        deferred(value);
      });
    }, 0);
  }
  fn(resolve);
}

异步操作成功之后,state会变成fulfilled,这之后then注册的回调函数都会立即执行。

以上基本实现了Promise的所有基础功能,但真正魔幻般的部分尚未开始,详见下篇~

参考资料剖析 Promise 之基础篇

上一篇下一篇

猜你喜欢

热点阅读