Promise的简易实现(2)

2018-07-14  本文已影响9人  SunnyEver0

在上一篇文章里面,我们实现了一个简单的Promise,已可以满足一些较简单的场景。但却无法进行then的Promise链式衔接,比如这样:

getUserId()
    .then(getUserInfoById)
    .then(function (info) {
        
    });

function getUserJobById(id) {
    return new Promise(function (resolve) {
        fetch(baseUrl + id, function(res) {
            resolve(res);
        });
    });
}

这种场景相信用过promise的人都知道会有很多,那么类似这种就是所谓的链式Promise

链式Promise是指在当前promise达到fulfilled状态后,即开始进行下一个promise(后邻promise)。那么我们如何衔接当前promise和后邻promise呢?(这是这里的难点)。

只需在then方法里面return一个promise就好啦。可见Promises/A+规范中的2.2.7
Promise/A+规范

then must return a promise [3.3].

function RPromise(fn) {
  var state = 'pending',
    value = null,
    callbacks = []; //callbacks为数组,因为可能同时有很多个回调


  this.then = function (onFulfilled) {
    return new RPromise(function (resolve) {
      handle({
        onFulfilled: onFulfilled || null,
        resolve: resolve
      });
    });
  };
  // this.then = function (onFulfilled) {
  //   if (state === 'pending') {
  //     callbacks.push(onFulfilled);
  //     //ask 为什么要return this?
  //     return this;
  //   }
  //   //假如state已经切换至其他状态,直接执行回调
  //     setTimeout(function () {
  //         onFulfilled(value);
  //     }, 0);
  //
  //   return this;
  // };
// 关键tip-2
// 1: 链式promise之间有一个桥梁promise,可称之为bridge promise,用于衔接两个promise,包装在then函数中
// 2: 当前一个promise resolve之后,bridge promise负责传递之前promise的值
// 3: 将当前promise的值和bridge promise的resolve方法传给下一个promise之后,在下一个promise resolve的时候,执行bridge promise的resolve方法,再执行本身后注册的then函数中的promise resolve
// 4: 执行完四个promise(promise 1 - getUserId, promise 2 - getUserId bridge, promise 3 - getUserInfoById, promise 4 - getUserInfoById bridge)之后,继续执行后面的then函数
  function handle(callback) {
    if (state === 'pending') {
      callbacks.push(callback);
      return;
    }
    //如果then中没有传递任何东西
    if (!callback.onFulfilled) {
      callback.resolve(value);
      return;
    }

    var ret = callback.onFulfilled(value);
    callback.resolve(ret);
  }

  function resolve(newValue) {

    state = 'fulfilled';
    value = newValue;

    // Promises/A+规范明确要求回调需要通过异步方式执行,用以保证一致可靠的执行顺序
    // 保证then函数的回调都已注册完毕
    // 比如promise内部的函数是同步函数
    // function getUserId() {
    //     return new Promise(function (resolve) {
    //         resolve(9876);
    //     });
    // }
    // getUserId().then(function (id) {
    //     // 一些处理
    // });

    if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
      var then = newValue.then;
      if (typeof then === 'function') {
        then.call(newValue, resolve);
        return;
      }
    }
    state = 'fulfilled';
    value = newValue;
    // console.log('value' + value);
    setTimeout(function () {
      callbacks.forEach(function (callback) {
        handle(callback);
      });
    }, 0);
  }

  fn(resolve);
}

//eg:
var testAsyncFunc1 = function () {
  return new RPromise(function (resolve) {
    // resolve(123);
    setTimeout(function () {
      resolve(123)
    }, 100)
  })
};

var testAsyncFunc2 = function (res) {
  return new RPromise(function (resolve) {
    setTimeout(function () {
      resolve(res + 456)
    }, 100);
  })
};

testAsyncFunc1()
  .then(testAsyncFunc2)
  .then(function (res) {
    console.log(res);
  });

console.log(456);

1.then方法中,创建并返回了新的Promise实例,这是串行Promise的基础,并且支持链式调用。
2.handle方法是promise内部的方法。then方法传入的形参onFulfilled以及创建新Promise实例时传入的resolve均被push到当前promise的callbacks队列中,这是衔接当前promise和后邻promise的关键所在(这里一定要好好的分析下handle的作用)。
3.testAsyncFunc1生成的promise(简称testPromise1)异步操作成功,执行其内部方法resolve,传入的参数正是异步操作的结果123
4.调用handle方法处理callbacks队列中的回调:testAsyncFunc2 方法,生成新的promise(testAsyncFunc2 promise)
5.执行之前由testAsyncFunc1 promise的then方法生成的新promise(称为bridge promise)的resolve方法,传入参数为testAsyncFunc1 promise。这种情况下,会将该resolve方法传入testAsyncFunc2 promise的then方法中,并直接返回。
6/在testAsyncFunc2 promise异步操作成功时,执行其callbacks中的回调:testAsyncFunc1 bridge promise中的resolve方法
7.最后执行testAsyncFunc1 bridge promise的后邻promise的callbacks中的回调。

// 关键tip-2
1: 链式promise之间有一个桥梁promise,可称之为bridge promise,用于衔接两个promise,包装在then函数中 2: 当前一个promise resolve之后,bridge promise负责传递之前promise的值
3: 将当前promise的值和bridge promiseresolve方法传给下一个promise之后,在下一个promise resolve的时候,执行bridge promiseresolve方法,再执行本身后注册的then函数中的promise resolve
4: 执行完四个promise(promise 1 - getUserId, promise 2 - getUserId bridge, promise 3 - getUserInfoById, promise 4 - getUserInfoById bridge)之后,继续执行后面的then函数

上一篇 下一篇

猜你喜欢

热点阅读