快速掌握Promise

前言:

面试会遇到Promise,问你是怎么理解Promise的?git

个人理解就是承诺!es6

编码代码,存在异步的地方都会遇到Promise! 搞了这么久,感受理解不是很透github

突然想起一句话:学习法语糖的最好方法,是本身去实现ta,本身实现不了,就看比人怎么实现的面试

基本用法:

let promise = new Promise(   function(resolve, reject) {
/* 异步操做 */  setTimeout(() => {
    let number = Math.floor(Math.random() * 3)
    if (number == 2) {
      resolve(number);
    } else {
      reject('不是2')
    }
  }, 3000);

}     )
promise.then( 
(value) => {// then方法第一个参数onFulfilled,异步任务成功时调用
  console.log(value);
}, 
(value) => {// then方法第二个参数onRejected,异步任务成功时调用
  console.log(value);
}
);
复制代码

根据上面的内容开始实现 Promise构造函数

function Promise(fn) {
    //校验
  if (!(this instanceof Promise))
    throw new TypeError('Promise 前面必须加new');
  if (typeof fn !== 'function') throw new TypeError('not a function');

  this._state = 0; // _state有三个值 0表明PENDING(进行中) 
                   //1表明FULFILLED (已成功) 
                   //2表明REJECTED(已失败)
                   //3表明传入resolve的是Promise实例
  this._value = undefined; //异步任务完成获取的值 reslove()或者reject()中传递的值
  this._deferreds = []; //存放then函数传递的回调

  doResolve(fn, this);
}
复制代码

根据上面的例子能够看到Promise构造函数的参数是一个包含异步任务的函数数组

有了构造函数,接下来实现doResolve(fn, this),doResolve要作两件事,第一要执行咱们传入的promise

包含异步任务的函数,同时传入resolve,reject参数 function(resolve, reject) {,能够看上线的例子bash

function doResolve(fn, self) {
  var done = false;
    fn(
      function(value) { //第一个参数resolve,当异步成功完成调用
        if (done) return;
        done = true;
        resolve(self, value);
      }, 
      function(reason) { //第二个参数reject,当异步完成失败调用
        if (done) return;
        done = true;
        reject(self, reason);
      }
    );
}
复制代码

其中利用闭包,保证传入的resolve,reject 只能调用一次,保持对self,Promise实例的引用闭包

接下来实现resolve,reject,方法只是记录下_state的状态dom

function resolve(self, newValue) {
    self._state = 1;
    self._value = newValue;
    finale(self);
}

function reject(self, newValue) {
  self._state = 2;
  self._value = newValue;
  finale(self);
}复制代码

实现finale,调用self._deferreds 存放then方法中传入的回调onFulfilled和onRejected异步

再没有调用then方法时,self._deferreds=[],当调用then 方法时判断self._state === 0是没有完成

就将then 方法的回调存入self._deferreds,若是已经完成,根据self._state为1或者2调用onFulfilled或者onRejected

function finale(self) {
  for (var i = 0, len = self._deferreds.length; i < len; i++) {
    handle(self, self._deferreds[i]);
  }
  self._deferreds = null;
}


function handle(self, deferred) {
  if (self._state === 0) {
    self._deferreds.push(deferred);
    return;
  }
  setTimeout(function() {
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    cb(self._value);
  }, 0);
}复制代码

实现then方法,当调用then 方法时判断self._state === 0是没有完成

就将then 方法的回调存入self._deferreds,若是已经完成,根据self._state为1或者2调用onFulfilled或者onRejected

Promise.prototype.then = function(onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  onRejected = typeof onRejected === 'function' ? onRejected : null;

  handle(this, {onFulfilled,onRejected});
}复制代码

基本的Promise就实现了,去掉不少细节

剩下的就是Promise的几个方法实现

Promise.prototype.catch = function(onRejected) {
  return this.then(null, onRejected);
};

Promise.resolve = function(value) {
  if (value && typeof value === 'object' && value.constructor === Promise) {
    return value;
  }

  return new Promise(function(resolve) {
    resolve(value);
  });
};

Promise.reject = function(value) {
  return new Promise(function(resolve, reject) {
    reject(value);
  });
};

Promise.race = function(values) {
  return new Promise(function(resolve, reject) {
    for (var i = 0, len = values.length; i < len; i++) {
      values[i].then(resolve, reject);
    }
  });
};
复制代码

这几个方法都很简单,复杂一点的是Promise.all;

Promise.all = function(arr) {
  return new Promise(function(resolve, reject) {
    if (!arr || typeof arr.length === 'undefined')
      throw new TypeError('Promise.all accepts an array');
    var args = Array.prototype.slice.call(arr);
    if (args.length === 0) return resolve([]);
    var remaining = args.length;

    function res(i, val) {
      try {
        if (val && (typeof val === 'object' || typeof val === 'function')) {
          var then = val.then;
          if (typeof then === 'function') {
            then.call(
              val,
              function(val) {
                res(i, val);
              },
              reject
            );
            return;
          }
        }
        args[i] = val;
        if (--remaining === 0) {
          resolve(args);
        }
      } catch (ex) {
        reject(ex);
      }
    }

    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });

复制代码

Promise.all传入的是一个Promise实例数组,经过计数方式当传入的Promise实例每完成一个--remaining,计数器减一,全部都完成了调用resolve触发then的回调

当你看完实现代码再结合阮一峰的讲解实例es6.ruanyifeng.com/#docs/promi…,应该能够更快的掌握


本文为了更好理解,省去了不少代码完整代码请查看promise-polyfill 

相关文章
相关标签/搜索