Анализ исходного кода промисов

JavaScript

предисловие

then/promiseпроект основан наPromises/A+стандартная реализацияPromiseбиблиотека, из этого проекта мы видимPromiseКаков принцип и как это делается, чтобы быть более знакомым сPromise

анализировать

Зная из index.js, он первым выводит./core.js, а затем каждый выполнял код другого файла черезrequeireМетоды.

Давайте сначала подумаем о самом простом использовании промисов.

new Promise((resolve, reject) =>  {
    resolve(4);

}).then(res => {
    console.log(res); // export 4
});

Критерии в обещаниях

Стандарт предусматривает:

  1. Начальное состояние объекта Promise:Pending, существованиеresolveилиreject, государство становитсяFulfilledилиRejected
  2. resolveполучить успешные данные,rejectПолучить ошибочные или неверные данные
  3. Promiseобъект должен иметьthenметод и принимает только два параметра функцииonFulfilled,onRejected

index.js

'use strict';

module.exports = require('./core.js');
require('./done.js');
require('./finally.js');
require('./es6-extensions.js');
require('./node-extensions.js');
require('./synchronous.js');

давайте сначала посмотримsrc/core.js

function Promise(fn) {
  // 判断 this一定得是object不然就会报错,这个方法一定得要new出来
  if (typeof this !== 'object') {
    throw new TypeError('Promises must be constructed via new');
  }
  // 判断fn 一定得是一个函数
  if (typeof fn !== 'function') {
    throw new TypeError('Promise constructor\'s argument is not a function');
  }
  this._deferredState = 0;
  this._state = 0;
  this._value = null;
  this._deferreds = null;
  if (fn === noop) return;
  // 最终doResolve很关键
  doResolve(fn, this);
}

PromiseЭто метод строительства, когда он начинается, он проверен, обеспеченfnэто функция, которая инициализирует некоторые переменные и, наконец, выполняетdoResolve()

Давайте посмотримdoResolveСюда.

/**
 * Take a potentially misbehaving resolver function and make sure
 * onFulfilled and onRejected are only called once.
 *
 * Makes no guarantees about asynchrony.
 */
// 
// 确保`onFulfilled`和`onRejected`方法只调用一次
// 不保证异步
function doResolve(fn, promise) {
  var done = false;
  var res = tryCallTwo(fn, function (value) {
    // 如果done 为true 则return
    if (done) return;
    done = true;
    // 回调执行 resolve()
    resolve(promise, value);
  }, function (reason) {
    // 如果done 为true 则return
    if (done) return;
    done = true;
    reject(promise, reason);
  });
  // res为truCallTwo()的返回值
  // 如果done没有完成 并且 res 是 `IS_ERROR`的情况下
  // 也会执行reject(),同时让done完成
  if (!done && res === IS_ERROR) {
    done = true;
    reject(promise, LAST_ERROR);
  }
}

doResolveСамым критическим является выполнениеtryCallTwoвторой и третий параметры этого метода являются обратными вызовами.doneверно, и каждый из них будет выполняться одновременноresolve()илиreject()метод. наконец, когдаtryCallTwoВозвращаемое значениеIS_ERROR, он также будет выполнятьсяreject()метод.

Давайте сначала посмотримtryCallTwoметод

function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

fnфактическиPromiseАнонимная функция при инициализации(resolve, reject) => {},a,bпредставляетresolve()а такжеreject()метод, когда мы закончим выполнение в обычном режимеpromiseфункция, выполнениеresolveзатем вdoResolve中, второй параметр, который мы выполнили в это время, вызывается обратно, если сообщается об ошибке,reject()выполняется, вызывается второй параметр. Наконец, исключение перехватывается, и при возникновении ошибки оноreturn IS_ERROR, когда это не ошибка, это будетreturn undinfed

вернуться к только чтоdoResolveметод, когда будет выполнен обратный вызов второго параметра, он будет выполненresolveметод

function resolve(self, newValue) {
  // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
  // 不能吃传递自己
  if (newValue === self) {
    // 报错
    return reject(
      self,
      new TypeError('A promise cannot be resolved with itself.')
    );
  }
  // promise作为参数
  if (
    newValue &&
    (typeof newValue === 'object' || typeof newValue === 'function')
  ) {
    // 获取它的promise方法 读取newValue.then
    var then = getThen(newValue);
    if (then === IS_ERROR) {
      // 如果then IS_ERROR
      return reject(self, LAST_ERROR);
    }
    if (
      // 如果then是self的then
      // 并且Promise
      then === self.then &&
      // newValue 属于Promise
      newValue instanceof Promise
    ) {
      // _state为3
      // 一般then之后走这里
      // 执行then(newValue)返回了promise
      self._state = 3;
      // selft.value为newValue
      self._value = newValue;
      // 当state为3时执行 finale
      finale(self);
      return;
    } else if (typeof then === 'function') {
      doResolve(then.bind(newValue), self);
      return;
    }
  }
  self._state = 1;
  self._value = newValue;
  finale(self);
}

без привязкиthenВ случае (то есть одногоthenВ случае, внутреннее состояние будет_stateустановлен в3назначить входящее значение внутренней переменной_valueв конечном итоге выполнитfinal()метод, иначе он будет использоватьdoResolveзвонитьthen

давайте посмотрим еще разreject

function reject(self, newValue) {
  // _state = 2为reject
  self._state = 2;
  self._value = newValue;
  if (Promise._onReject) {
    Promise._onReject(self, newValue);
  }
  finale(self);
}

существуетrejectсреди наших_stateПоменял на 2, такой же последнийfinaleназывается.

Давайте взглянемfinaleфункция

// 执行自己的deferreds
function finale(self) {
  if (self._deferredState === 1) {
    handle(self, self._deferreds);
    self._deferreds = null;
  }
  if (self._deferredState === 2) {
    for (var i = 0; i < self._deferreds.length; i++) {
      // 遍历handle
      handle(self, self._deferreds[i]);
    }
    // 将deferred 置空
    self._deferreds = null;
  }
}

В этом методе, по разным_deferredState, будет выполнять различныеhandleметод.

Давайте посмотримhandleметод

function handle(self, deferred) {
  while (self._state === 3) {
    self = self._value;
  }
  // 如果有onHandle方法 则执行该方法
  if (Promise._onHandle) {
    Promise._onHandle(self);
  }
  // (初始 _state 为0)
  if (self._state === 0) {
    // (初始 _deferredState 为0)
    if (self._deferredState === 0) {
      self._deferredState = 1;
      self._deferreds = deferred;
      return;
    }
    // 如果 _deferredState是1 则__deferreds是一个数组
    if (self._deferredState === 1) {
      self._deferredState = 2;
      self._deferreds = [self._deferreds, deferred];
      return;
    }
    // 当走到这里 _deferredState应该是2 将deferred
    // 插入到数组当中
    self._deferreds.push(deferred);
    return;
  }
  handleResolved(self, deferred);
}

Ключ здесь должен быть в том, чтобы пройтиdeferredStateразные состояния, т.deferredположить вdeferredsсреди. Также когда наш_stateне для0, в конечном итоге выполнитhandleResolved.

Продолжай читатьhandleResolve()метод

function handleResolved(self, deferred) {
  asap(function() {
    // _state为1时,cb = onFulfilled 否则 cb = onRejected
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {
      if (self._state === 1) {
        resolve(deferred.promise, self._value);
      } else {
        reject(deferred.promise, self._value);
      }
      return;
    }
    var ret = tryCallOne(cb, self._value);
    if (ret === IS_ERROR) {
      reject(deferred.promise, LAST_ERROR);
    } else {
      resolve(deferred.promise, ret);
    }
  });
}.then((res) => {
}).catch((error) => {
})

В этом методе он будет выполняться в соответствии с различными состояниями нашей задачи (_state).onFulfilledилиonRejectedметод. Когда этот метод вызывается, это наш простойPromiseконец.

Вернемся к тому, что я только что сказалPromiseВ конце конструктора

уже настроенPromiseнекоторые переменные функции

Promise._onHandle = null;
Promise._onReject = null;
Promise._noop = noop;

затем вPromiseустановлен на прототипеthenметод.

Promise.prototype.then = function(onFulfilled, onRejected) {
  // 首先看这是谁构造的 如果不是promise
  // 则return 执行safeThen
  if (this.constructor !== Promise) {
    return safeThen(this, onFulfilled, onRejected);
  }
  // 如果是则初始化一个Promise 但是参数 noop 为空对象 {}
  var res = new Promise(noop);
  // 随后执行handle方法
  handle(this, new Handler(onFulfilled, onRejected, res));
  return res;
};

существуетthenЭтот метод сначала определяет, является лиPromiseпостроен, если нет, вернуть и выполнитьsafeThen, иначе выполнитьPromiseпостроитьresобъект, а затем выполнитьhandleметод и, наконец,promiseПеременнаяresвернуть.handleметод упоминался ранее, здесь, при инициализации_stateа также_deferredпреобразуются в0, так и будетdefrredСохранитьpromiseсреди.

Взгляните на вышеsafeThenметод

function safeThen(self, onFulfilled, onRejected) {
  return new self.constructor(function (resolve, reject) {
    var res = new Promise(noop);
    res.then(resolve, reject);
    handle(self, new Handler(onFulfilled, onRejected, res));
  });
}

обработать

нужно иметь одинPromiseконструктор, который в конечном итоге выполнит свои аргументы(resolve, reject) => {}, заявленоthenметод пройдетhandle()метод будетonFulfilledа такжеonRejectedметод сохранен. при внешнем вызовеresolveилиonRejected, в конечном итоге выполнитhandleТем не менее, он, наконец, будет выполнен в соответствии с состояниемonFulfilledилиonRejected. таким образом, к нашемуthenПерезваниваю.

Расширения обещаний

done

правильноdoneрасширениеsrc/done.jsсреди

'use strict';

var Promise = require('./core.js');

module.exports = Promise;
Promise.prototype.done = function (onFulfilled, onRejected) {
  var self = arguments.length ? this.then.apply(this, arguments) : this;
  self.then(null, function (err) {
    setTimeout(function () {
      throw err;
    }, 0);
  });
};

выполняется внутреннеthen()

finally

правильноfinallyрасширениеsrc/finally.jsсреди

существуетPromiseсреди стандартов, сам по себе неfinallyметод, но вES2018Стандарт имеет,finallyРеализация выглядит следующим образом

'use strict';

var Promise = require('./core.js');

module.exports = Promise;
Promise.prototype.finally = function (callback) {
  return this.then(function (value) {
    return Promise.resolve(callback()).then(function () {
      return value;
    });
  }, function (err) {
    return Promise.resolve(callback()).then(function () {
      throw err;
    });
  });
};

PromiseизonFulfilledа такжеonRejectedНезависимо от того, какой обратный вызов вызывается, он в конечном итоге сработаетcallbackПерезвоните. Еще одна вещь, которую следует отметить, это то, чтоfinallyВозвращение также являетсяPromise.

es6-extensions.js

существуетes6-extensions.jsФайл содержит некоторые расширения для ES6.

Promise.resolve

function valuePromise(value) {
  var p = new Promise(Promise._noop);
  // 将_state赋值为 非0
  // _value进行保存
  p._state = 1;
  p._value = value;
  // 这样做的目的是省略的一些前面的逻辑
  return p;
}

Promise.resolve = function (value) {
  if (value instanceof Promise) return value;

  if (value === null) return NULL;
  if (value === undefined) return UNDEFINED;
  if (value === true) return TRUE;
  if (value === false) return FALSE;
  if (value === 0) return ZERO;
  if (value === '') return EMPTYSTRING;

  // value return new Promise
  if (typeof value === 'object' || typeof value === 'function') {
    try {
      var then = value.then;
      if (typeof then === 'function') {
        // 返回 返回了一个新的Promise对象
        return new Promise(then.bind(value));
      }
    } catch (ex) {
        // 如果报错 则返回一个就只
      return new Promise(function (resolve, reject) {
        reject(ex);
      });
    }
  }

  return valuePromise(value);
};

Promise.reject

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

Promise.all

Promise.all = function (arr) {
  // 类似深拷贝了一份给了args
  var args = Array.prototype.slice.call(arr);

  return new Promise(function (resolve, reject) {
    // 判断了all的promise数量
    if (args.length === 0) return resolve([]);
    // remaining则是promise数组的长度
    var remaining = args.length;
    // i为index val 为 promise
    function res(i, val) {
      if (val && (typeof val === 'object' || typeof val === 'function')) {
        if (val instanceof Promise && val.then === Promise.prototype.then) {
          while (val._state === 3) {
            val = val._value;
          }
          if (val._state === 1) return res(i, val._value);
          if (val._state === 2) reject(val._value);
          // val._state 为 0时 走这里
          val.then(function (val) {
            res(i, val);
          }, reject);
          return;
        } else {
          var then = val.then;
          if (typeof then === 'function') {
            var p = new Promise(then.bind(val));
            p.then(function (val) {
              res(i, val);
            }, reject);
            return;
          }
        }
      }
      args[i] = val;
      // 当所有的promise执行完 则是remaining为0
      // 则执行resolve();
      if (--remaining === 0) {
        resolve(args);
      }
    }
    // 遍历所有的promise
    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });
};

Promise.all()также возвращаетPromiseфункция. есть один внутриremainingПеременная выполняется каждый раз, когдаpromiseПосле функции она будет уменьшена на единицу, когда всеpromiseПосле выполнения он выполнит свой собственныйresolve.

Promise.race

Promise.race = function (values) {
  return new Promise(function (resolve, reject) {
    values.forEach(function(value){
      Promise.resolve(value).then(resolve, reject);
    });
  });
};

перебирать входящиеpromiseмассив, послеPromise.resolve(value)Исходный код можно увидеть, еслиvalueЯвляетсяPromiseзатем пользователь напрямую преобразует этоvaluereturn, последний в массивеpromiseВыполняется обратный вызов, который имеет приоритет.

Promise.property.catch

catchВ стандарте нет стандарта, хотя мы используем больше

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

catchОбратный вызов на самом делеthen(null, onRejected)Перезвоните.

Широкая реклама

Эта статья была опубликована вЕженедельный выпуск Mint Front End, Добро пожаловать в Watch & Star ★, пожалуйста, указывайте источник при перепечатке.

Добро пожаловать, чтобы обсудить, поставить лайк и перейти 。◕‿◕。~