Исходный код обещания: затем цепочка вызовов

внешний интерфейс исходный код Promise

предисловие

Следующее, что нужно углубить, это цепной вызов then, который является самой запутанной частью реализации. Прежде чем читать, давайте углубимся в впечатление.

constructor -> fn --同步--> resolve(reject) -> then -> then 回调
constructor -> fn --异步--> then -> resolve(reject) -> then 回调

Будь то синхронный или асинхронный,then 回调函数будет вresolveПосле того, как он будет выполнен, он будет выполнен. Таким образом, можно понять, что только выполняяresolveПосле этого сработаетthen 回调函数исполнение.

Примечание. На этот раз я прочитал версию 3.0.0 then/promise, пожалуйста, отметьте исходный код.здесь.

интерпретировать

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

var p1 = new Promise(function (resolve) {
  setTimeout(function () {
    resolve(1);
  }, 1000);
})

p1.then(function (val) {
  var p3 = new Promise(function (resolve) {
    setTimeout(function () {
      resolve(val + 1);
    }, 1000);
  });

  return p3;
}).then(function (val) {
  console.log(val);
});

Глядя на приведенный выше код, мы ясно видим, что были добавлены два новых экземпляра Promise, соответственно, с использованиемp1а такжеp3Выражать. Затем из предыдущей реализации метода then мы увидим, что он также возвращает экземпляр Promise, мы используемp2Для представления экземпляра Promise, возвращаемого после выполнения функции then, для следующего различия.

this.then = function(onFulfilled, onRejected) {
  return new Promise(function(resolve, reject) {
    handle({ onFulfilled: onFulfilled, onRejected: onRejected, resolve: resolve, reject: reject })
  })
}

Столкнувшись с приведенным выше кодом, давайте посмотрим, что представляют собой переменные:

  • p1: самый внешний экземпляр Promise;
  • p2: Экземпляр Promise, возвращенный p1, вызвавшим функцию then;
  • p3: Экземпляр Promise, возвращенный функцией обратного вызова then для p1.

исполнительный лист

Рассмотрим порядок выполнения приведенного выше примера кода:

  1. Новый экземпляр Promise назначается p1, и выполняется функция fn;
  2. p1 вызывает свою функцию then, которая возвращает p2;
  3. p2 вызывает свою функцию then (которая фактически возвращает новый экземпляр Promise);
  4. Через одну секунду выполните функцию разрешения p1;
  5. Запускает функцию обратного вызова p1, после чего создается и возвращается p3;
  6. Еще через секунду p3 выполняет функцию разрешения;
  7. Запустите p2, затем функцию обратного вызова.

Сомнение: здесь p3 выполняет свою функцию разрешения, как он может вызвать функцию обратного вызова p2, не должен ли он запускать свою собственную функцию обратного вызова? ?

handle

Посмотрите на код из шага 5, вызовите функцию обратного вызова then для p1, а также вызовите функцию дескриптора в p1:

function handle(deferred) {
  nextTick(function() {
    var cb = state ? deferred.onFulfilled : deferred.onRejected
    if (typeof cb !== 'function'){
      (state ? deferred.resolve : deferred.reject)(value)
      return
    }
    var ret
    try {
      ret = cb(value)
    }
    catch (e) {
      deferred.reject(e)
      return
    }
    deferred.resolve(ret)
  })
}

будет выполняться первымonFulfilledфункция, то естьp1Функция обратного вызова then, созданная в это времяp3Возвращает назначение ret. Затем вызовите разрешение deferred, которое на самом деле вызываетp2решить, будетp3Передать в качестве параметра.

resolve

Отложенные вызовы разрешаются, и сначала удаляется код, который не будет выполняться:

function resolve(newValue) {
  if (delegating)
    return
  resolve_(newValue)
}

function resolve_(newValue) {
  if (state !== null)
    return
  try {
    if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.')
    if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
      var then = newValue.then
      if (typeof then === 'function') {
        delegating = true
        then.call(newValue, resolve_, reject_)
        return
      }
    }
  } catch (e) { reject_(e) }
}

потому что новое значениеp3, посчитав, что это объект с then, будет вызвана его функция then, котораяp2разрешение_ какp3Затем передается функция обратного вызова.

еслиp3Когда разрешение выполнено, будет выполнена его функция обратного вызова, т.е.p2разрешение_. еслиp2При выполнении resolve_ будет выполнена его собственная функция обратного вызова.

Здесь вы можете думать о коде так: все переменные в resolve_p2Переменные:

then.call(newValue, function resolve_ (newValue) {
  // 更新状态
  state = true

  // 记住 resolve 的参数
  value = newValue
  finale()
}, reject_);

а такжеp2Функция обратного вызова then — это связанная функция обратного вызова then в примере кода. Таким образом, реализован цепной вызов then.

Сказав кучу слов выше, это может быть немного сложно понять.Давайте сделаем снимок, чтобы понять это.

delegating

Коротко о переменныхdelegating,потому чтоp2Разрешение_ может быть вызвано вызовом разрешения или вызовомp3затем обратный вызов для запуска. когда прошлоp3тогда обратный вызов для запуска, когдаdelegatingбудет установлено значение true, в этот момент он будет отключенp2Случай, вызванный вызовом разрешения.

function resolve(newValue) {
  if (delegating)
    return
  resolve_(newValue)
}

nextTick

Зная порядок всего тогдашнего цепного звонка, давайте взглянем на него в последний раз.nextTick. В моем понимании использованиеnextTickПричина в том, что функция обратного вызова then не будет выполняться до тех пор, пока не будет выполнен весь код then.

В противном случае следующий код,p1Функция обратного вызова выполняется первой, а затем выполняется вторая функция, что нарушает концепцию, согласно которой Promise — это очередь микрозадач в ES6.

var p1 = new Promise(function (resolve) {
  resolve(1);
})

p1.then(function (val) {
  var p3 = new Promise(function (resolve) {
    resolve(val + 1);
  });

  return p3;
}).then(function (val) {
  console.log(val);
});

Суммировать

Цепной вызов промиса then заключается в простом использовании нового экземпляра промиса в качестве моста.Когда промис, возвращенный в предыдущей функции обратного вызова then, разрешается, он запускает мост для выполнения своего обратного вызова then.

Если это немного сложно понять, не волнуйтесь, прочитайте статью несколько раз, чтобы понять это.