предисловие
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
});
Критерии в обещаниях
Стандарт предусматривает:
- Начальное состояние объекта Promise:
Pending, существованиеresolveилиreject, государство становитсяFulfilledилиRejected -
resolveполучить успешные данные,rejectПолучить ошибочные или неверные данные -
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 ★, пожалуйста, указывайте источник при перепечатке.