предисловие
Я считаю, что все часто используютPromiseили используйтеGenerator,asnyc/awaitи т.д. Асинхронные решения, онлайнPromiseПринципы расцветают повсюду.
Я всегда хотел найти время, чтобы написатьPromiseПонял, но обычная работа тоже очень загружена.Выпало 3 дня выходных на Новый год, а перерыв 2,5 дня.Полдня взял посмотреть.Promise.
Как использовать обещания
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000)
}).then((data) => {
console.log(data);
return new Promise((res) => {
setTimeout(() => {
res(2);
},1000)
})
}).then((res) => {
console.log(res);
})
период, термин
-
Promiseявляется совместимымpromiseТехнические характеристикиthenметод объекта или функции. -
thenableвключенthenметод объекта или функции. -
valueлюбойJavascriptстоимость. (включатьundefined,thenable,PromiseЖдать). -
exceptionКthrowЗначение, выдаваемое выражением. -
reasonэто описаниеPromiseЗначение причины отказа.
из-заPromise/A+Спецификация не включаетcatch,race,allИ других способов добиться, так что тут подробно не объяснять.
Требовать
ОдинPromiseДолжен находиться в одном из следующих состояний:pending, fulfilledилиrejected.
еслиpendingстатус, тоpromise:
может быть преобразован вfulfilledилиrejectedусловие.
еслиfulfilledстатус, тоpromise:
- Невозможно перейти в любое другое состояние.
- Должно быть значение, и это значение нельзя изменить.
еслиrejectedстатус, тоpromiseМогу:
- Невозможно перейти в любое другое состояние.
- Должна быть причина, и это значение нельзя изменить.
function MyPromise(callback) {
let that = this;
//定义初始状态
//Promise状态
that.status = 'pending';
//value
that.value = 'undefined';
//reason 是一个用于描述Promise被拒绝原因的值。
that.reason = 'undefined';
//定义resolve
function resolve(value) {
//当status为pending时,定义Javascript值,定义其状态为fulfilled
if(that.status === 'pending') {
that.value = value;
that.status = 'resolved';
}
}
//定义reject
function reject(reason) {
//当status为pending时,定义reason值,定义其状态为rejected
if(that.status === 'pending') {
that.reason = reason;
that.status = 'rejected';
}
}
//捕获callback是否报错
try {
callback(resolve, reject);
} catch (error) {
reject(error);
}
}
Promiseобъект имеетthenметод, используемый для регистрации в этомPromiseОбратный вызов после определения статуса,thenМетод принимает два параметра:Promise.then(onFulfilled,onRejected).
Мы пишем функцию then на прототипе.
MyPromise.prototype.then = function(onFulfilled, onRejected) {
let that = this;
if(that.status === 'resolved') {
onFulfilled(that.value);
}
if(that.status === 'rejected') {
onRejected(that.reason);
}
}
Приведенный выше код просто реализуетPromiseСамая основная логика , если вы напрямую вызываетеthenявляется исполняемым, но не поддерживает асинхронность, иPromiseСамая большая особенность - решитьcallbackПроблема с адским асинхронным обратным вызовом.
Итак, переделываем.
function MyPromise(callback) {
let that = this;
//定义初始状态
//Promise状态
that.status = 'pending';
//value
that.value = 'undefined';
//reason 是一个用于描述Promise被拒绝原因的值。
that.reason = 'undefined';
//用来解决异步问题的数组
that.onFullfilledArray = [];
that.onRejectedArray = [];
//定义resolve
function resolve(value) {
//当status为pending时,定义Javascript值,定义其状态为fulfilled
if(that.status === 'pending') {
that.value = value;
that.status = 'resolved';
that.onFullfilledArray.forEach((func) => {
func(that.value);
});
}
}
//定义reject
function reject(reason) {
//当status为pending时,定义reason值,定义其状态为rejected
if(that.status === 'pending') {
that.reason = reason;
that.status = 'rejected';
that.onRejectedArray.forEach((func) => {
func(that.reason);
});
}
}
//捕获callback是否报错
try {
callback(resolve, reject);
} catch (error) {
reject(error);
}
}
thenмодификация функции
MyPromise.prototype.then = function(onFulfilled, onRejected) {
let that = this;
//需要修改下,解决异步问题,即当Promise调用resolve之后再调用then执行onFulfilled(that.value)。
//用两个数组保存下onFulfilledArray
if(that.status === 'pending') {
that.onFullfilledArray.push((value) => {
onFulfilled(value);
});
that.onRejectedArray.push((reason) => {
onRejected(reason);
});
}
if(that.status === 'resolved') {
onFulfilled(that.value);
}
if(that.status === 'rejected') {
onRejected(that.reason);
}
}
из-заPromise/A+Спецификация предусматриваетPromiseДолжен находиться в одном из следующих состояний:pending, fulfilledилиrejected, поэтому, когда пользователь используетPromiseКогда написан асинхронный код, то в это времяPromiseдолжен быть вpendingСтатус, в остальном нормальный звонок.
Поэтому инициализируйтеPromise, определите два массива какonFullfilledArray,onRejectedArray, сохранитьthenДве функции обратного вызова функцииonFulfilledа такжеonRejected. В то же время мыthenСуждение в функцииstatusтак или иначеpending,ПотомonFulfilledа такжеonRejectedв соответствующие массивы соответственно. когда пользователь звонитresolveилиreject, изменить состояние, перебрать массив, выполнитьonFulfilledилиonRejected, который вызывается асинхронно.
Цепные вызовы функции then
существуетPromise/A+В спецификации:
Для промиса его метод then может вызываться несколько раз.
- когда
promisefulfilledпосле всегоonFulfilledВсе должно быть выполнено в том порядке, в котором они были зарегистрированы. - когда
promiserejectedпосле всегоOnRejectedВсе должно быть выполнено в том порядке, в котором они были зарегистрированы.
затем должен вернуть обещание
- если
onFulfilledилиonRejectedвозвращаемое значениеx, затем выполнитеPromiseПроцесс разбора[[Resolve]](promise2, x). - если
onFulfilledилиonRejectedИсключение было брошеноe, ноpromise2должно бытьeдляreasonбыть отвергнутым. - если
onFulfilledне является функцией иpromise1ужеfulfilled,ноpromise2должен начинаться сpromise1значениеfulfilled. - если
OnRejectне является функцией иpromise1ужеrejected, ноpromise2должно быть таким жеreasonбыть отвергнутым.
MyPromise.prototype.then = function(onFulfilled, onRejected) {
let that = this;
let promise2;
// 根据标准,如果then的参数不是function,则我们需要忽略它
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(f) {};
onRejected = typeof onRejected === 'function' ? onRejected : function(r) {};
//需要修改下,解决异步问题,即当Promise调用resolve之后再调用then执行onFulfilled(that.value)。
//用两个数组保存下onFulfilledArray
if(that.status === 'pending') {
return promise2 = new Promise(function(resolve, reject) {
that.onFullfilledArray.push((value) => {
try {
let x = onFulfilled(that.value);
//判断onFulfilled是否是一个Promise,如果是,那么就直接把MyPromise中的resolve和reject传给then;
//返回值是一个Promise对象,直接取它的结果做为promise2的结果
if(x instanceof MyPromise) {
x.then(resolve, reject);
}
//否则,以它的返回值做为promise2的结果
resolve(x);
} catch (error) {
reject(error);
}
});
that.onRejectedArray.push((value) => {
try {
let x = onRejected(that.value);
//判断onRejected是否是一个Promise,如果是,那么就直接把MyPromise中的resolve和reject传给then;
//返回值是一个Promise对象,直接取它的结果做为promise2的结果
if(x instanceof MyPromise) {
x.then(resolve, reject);
}
//否则,以它的返回值做为promise2的结果
resolve(x);
} catch (error) {
reject(error);
}
});
})
}
if(that.status === 'fulfilled') {
return promise2 = new MyPromise(function(resolve, reject) {
try {
let x = onFulfilled(that.value);
//判断onFulfilled是否是一个Promise,如果是,那么就直接把MyPromise中的resolve和reject传给then;
//返回值是一个Promise对象,直接取它的结果做为promise2的结果
if(x instanceof MyPromise) {
x.then(resolve, reject);
}
//否则,以它的返回值做为promise2的结果
resolve(x);
} catch (error) {
reject(error);
}
})
}
if(that.status === 'rejected') {
return new MyPromise(function(resolve, reject) {
try {
let x = onRejected(that.value);
//判断onRejected是否是一个Promise,如果是,那么就直接把MyPromise中的resolve和reject传给then;
//返回值是一个Promise对象,直接取它的结果做为promise2的结果
if(x instanceof MyPromise) {
x.then(resolve, reject);
}
//否则,以它的返回值做为promise2的结果
resolve(x);
} catch (error) {
reject(error);
}
})
}
}
вызовthenкогда, судитьonFulfilledа такжеonRejectedЯвляется ли это функцией, если нет, возвращайте анонимную функцию и должны возвращать значение каждого параметра, используемого для решения цепочки вызовов.PromiseЗначение претендента.
Например:
new MyPromise(resolve=>resolve(8))
.then()
.then()
.then(function foo(value) {
alert(value)
})
Итак, мы изменили блок на этот:
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(f) { return f};
onRejected = typeof onRejected === 'function' ? onRejected : function(r) {throw r};
Но это нужно переписывать каждый разxа такжеMyPromiseотношения, поэтому нам нужно абстрагировать этот фрагмент кода, этот фрагмент кода вPromise/A+называется в спецификацииresolvePromise.
function resolvePromise(promise, x, resolve, reject) {
let then,thenCalledOrThrow = false
//如果promise 和 x 指向相同的值, 使用 TypeError做为原因将promise拒绝。
if (promise === x) {
return reject(new TypeError('Chaining cycle detected for promise!'))
}
//判断x是否是一个Promise,如果是,那么就直接把MyPromise中的resolve和reject传给then;
//返回值是一个Promise对象,直接取它的结果做为promise2的结果
if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
try {
then = x.then
if (typeof then === 'function') { // typeof
//x.then(resolve, reject);
then.call(x, function rs(y) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return resolvePromise(promise, y, resolve, reject)
}, function rj(r) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return reject(r)
})
} else {
return resolve(x)
}
} catch(e) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return reject(e)
}
} else {
return resolve(x)
}
}
thenНаконец, функция изменена на:
MyPromise.prototype.then = function(onFulfilled, onRejected) {
let that = this;
let promise2;
// 根据标准,如果then的参数不是function,则我们需要忽略它
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(f) { return f};
onRejected = typeof onRejected === 'function' ? onRejected : function(r) {throw r};
//需要修改下,解决异步问题,即当Promise调用resolve之后再调用then执行onFulfilled(that.value)。
//用两个数组保存下onFulfilledArray
if(that.status === 'pending') {
return promise2 = new Promise(function(resolve, reject) {
that.onFullfilledArray.push((value) => {
try {
let x = onFulfilled(value);
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
return reject(e)
}
});
that.onRejectedArray.push((value) => {
try {
let x = onRejected(value);
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
return reject(e)
}
});
})
}
if(that.status === 'fulfilled') {
return promise2 = new MyPromise(function(resolve, reject) {
try {
let x = onFulfilled(that.value);
//处理then的多种情况
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error);
}
})
}
if(that.status === 'rejected') {
return new MyPromise(function(resolve, reject) {
try {
let x = onRejected(that.value);
//处理then的多种情况
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
}
есть тест:
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000)
}).then((data) => {
console.log(data);
return new MyPromise((res) => {
setTimeout(() => {
res(2);
},1000)
})
}).then((res) => {
console.log(res);
})
//1
//2
наконец
Обещайте адрес GITHUB.
Использованная литература:
«Обещание / Спецификация A +»
"Обещание3"
«Реализация промиса, полностью соответствующего спецификации Promise/A+»
«Анализируйте внутреннюю структуру Promise, шаг за шагом, чтобы создать полный класс Promise, способный пройти все тестовые случаи»