напишите в начале
- Я видел несколько технических групп за последние несколько дней
PromiseНекоторые связанные реализации, я недавно смотрел на нихES6Некоторое содержание, так что я планирую разобраться сам, чтобы улучшить свое понимание; - Эта статья подходит для некоторых людей, которые знают и используют
Promiseлюди, если вы не знаете или не используетеPromise, рекомендуется посмотретьОбещание Руана Ифэна о начале работы с ECMAScript6.
чтоPromise
- Решение для асинхронного программирования;
-
Promiseэто контейнер, содержащий результат события (обычно асинхронной операции), которое завершится в будущем;
Функции
- На состояние объекта не влияет внешний мир.
PromiseОбъект представляет собой асинхронную операцию и имеет три состояния:pending(в ходе выполнения),fulfilled(успешно) иrejected(не удалось). - Однажды состояние изменилось, оно больше не изменится, и этот результат можно получить в любой момент.
PromiseЕсть только две возможности для изменения состояния объекта: отpendingсталиfulfilledи изpendingсталиrejected.
Простая реализация
Анализ процесса
- Источник изображенияMDN
инициализироватьPromise
- оригинальный
Promise
// Promise构造函数接收一个executor函数,executor函数执行完同步或异步操作后,调用它的两个参数resolve和reject
const promise = new Promise(function(resolve, reject) {
/*
如果操作成功,调用resolve并传入value
如果操作失败,调用reject并传入reason
*/
})
- содержит текущее состояние
- текущая стоимость
-
fulfilledмассив callback-функций -
rejectedмассив callback-функций
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const NewPromise = function(executor) {
const _this = this;
_this.status = PENDING; // 状态
_this.data = undefined; // 值
_this.onResolvedCallback = []; // fulfilled的回调函数数组
_this.onRejectedCallback = []; // rejected的回调函数数组
// 成功
function resolve(value) { ... }
// 失败
function reject(reason) { ... }
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
Полныйresoleа такжеreject
-
resoleявляется успешным вызовом и не требует изменения состояния дляfulfilled, то текущее значение устанавливается на входящее значение, и выполняется обходonResolvedCallbackобратный звонок в .
// 成功
function resolve(value) {
只有pending状态才能转换为fulfilled / rejected
setTimeout(function() { // 异步执行所有的回调函数
if (_this.status === PENDING) {
_this.status = FULFILLED;
_this.data = value;
_this.onResolvedCallback.forEach(callback => callback(value));
}
});
}
-
rejectреализация иresolveАналогично, только состояние изменяется наrejectedи реализацияonRejectedCallback.
// 失败
function reject(reason) {
setTimeout(function() { // 异步执行所有的回调函数
if (_this.status === PENDING) {
_this.status = REJECTED;
_this.data = reason;
_this.onRejectedCallback.forEach(callback => callback(reason));
}
});
}
- Основы теперь реализованы
Promise, вы можете использовать какPromiseИспользуйте его таким же образом, но еще не добавляйте другой метод.
// 测试
const promise = new NewPromise(function(resolve, reject) {
console.log('ss', 11)
})
thenметод
-
Promiseобъект имеетthenМетод, используемый в этой регистрацииPromiseОбратный вызов после определения состояния.thenМетод нужно прописать на цепочке прототипов (почему на прототипе непонятно, может надо дополнитьJavaScriptбазовый). существуетPromise/Aстандартный, четко оговариваетсяthenВозвращать новый объект, поэтому в нашей реализации также возвращаем новый объект.
// then挂载到原型上
NewPromise.prototype.then = function(onResolved, onRejected) {
const _this = this;
if ( typeof onResolved !== 'function') {
onResolved = function(value) { return value }
}
if ( typeof onRejected !== 'function') {
onRejected = function(reason) { throw reason }
}
// 公共判断
const common = function (data, resolve, reject) {
// 考虑到有可能throw,我们将其包在try/catch块里
try {
let value = _this.status === FULFILLED
? onResolved(data)
: onRejected(data)
if( value instanceof Promise) {
value.then(resolve, reject)
}
resolve(value)
} catch (error) {
reject(error)
}
}
// 公共判断
const pendingCommon = function (data, flag, resolve, reject) {
// 考虑到有可能throw,我们将其包在try/catch块里
try {
let value = flag === FULFILLED
? onResolved(data)
: onRejected(data)
if( value instanceof Promise) {
value.then(resolve, reject)
}
resolve(value)
} catch (error) {
reject(error)
}
}
if (_this.status === PENDING) {
return new NewPromise(function(resolve, reject) {
_this.onResolvedCallback.push((value) => {
pendingCommon(value, FULFILLED, resolve, reject);
})
_this.onRejectedCallback.push((reason) => {
pendingCommon(reason, REJECTED, resolve, reject);
})
})
} else { // resolve / reject
return new NewPromise(function (resolve, reject) {
setTimeout(function () {
common(_this.data, resolve, reject)
})
})
}
}
правильноresolveМетод снова усовершенствован
- судить
rosolveЯвляется ли значениеPromise,еслиPromiseПродолжать.thenметод.
// 成功
function resolve(value) {
// value 如果是Promise继续执行.then
+ if (value instanceof Promise) {
+ return value.then(resolve, reject)
+ }
...
}
catchметод
- захватывать
Promiseошибка исключения.
// catch方法
NewPromise.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}
finallyметод
-
finally()метод используется, чтобы указать, является лиPromiseОперация будет выполнена независимо от конечного состояния объекта.
// finally
NewPromise.prototype.finally = function (fun) {
return this.then((value) => {
return NewPromise.resolve(fun()).then(() => value);
}, (err) => {
return NewPromise.resolve(fun()).then(() => {
throw err;
});
});
};
resolveметод
- Существующие объекты преобразуются в
Promiseобъект, состояние экземпляраfulfilled.
NewPromise.resolve = function(value) {
if (value instanceof Promise) return value;
if (value === null) return null;
// 判断如果是promise
if (typeof value === 'object' || typeof value === 'function') {
try {
// 判断是否有then方法
let then = value.then;
if (typeof then === 'function') {
return new NewPromise(then.call(value)); // 执行value方法
}
} catch (e) {
return new NewPromise( (resolve, reject) =>{
reject(e);
});
}
}
return new NewPromise( (resolve, reject) =>{
resolve(value);
});
}
rejectметод
- Существующие объекты преобразуются в
Promiseобъект, состояние экземпляраrejected. достичь иresolveМетод аналогичен, и окончательный возврат изменен наreject.
NewPromise.reject = function(reason) {
...
return new NewPromise( (resolve, reject) =>{
reject(reason);
});
}
allметод
-
Promise.allМетод используется для переноса нескольких экземпляров Promise в новый.PromiseЭкземпляр; аргументы метода не могут быть массивами, но должны иметьIteratorинтерфейс, и каждый возвращаемый элементPromiseпример.
// all
NewPromise.all = function(promises) {
return new NewPromise((resolve, reject) => {
const result = []
// 判断参数属否是数组
promises = Array.isArray(promises) ? promises : []
const len = promises.length;
if(len === 0) resolve([]);
let count = 0
for (let i = 0; i < len; ++i) {
if(promises[i] instanceof Promise) {
promises[i].then(value => {
count ++
result[i] = value
if (count === len) resolve(result)
}, reject)
} else {
count ++
result[i] = promises[i]
if (count === len) resolve(result)
}
}
})
}
raceметод
-
Promise.race()Метод также заключается в объединении несколькихPromiseэкземпляр, завернутый в новыйPromiseпример. - Пока один из параметров первым меняет состояние,
Promise.race()статус меняется соответственно. Первый, кто изменилPromiseВозвращаемое значение экземпляра передается вPromise.race()функция обратного вызова.
// race
NewPromise.race = function (promises) {
return new NewPromise((resolve, reject) => {
promises = Array.isArray(promises) ? promises : []
promises.forEach(promise => {
promise.then(resolve, reject)
})
})
}
deferredметод
- Возвращает объект с помощью метода обещания.
// defered
NewPromise.deferred = function() {
const dfd = {}
dfd.promise = new NewPromise(function(resolve, reject) {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
allSettledметод
-
Promise.allSettled()метод принимает наборPromiseэкземпляр как параметр, завернутый в новыйPromiseэкземпляр, экземпляр оболочки не завершится, пока все эти экземпляры параметров не вернут результаты, независимо от того, выполнены они или отклонены. Возвращает массив, содержащий все результаты.
NewPromise.allSettled = function (promises) {
return new NewPromise((resolve, reject) => {
promises = Array.isArray(promises) ? promises : []
let len = promises.length;
const argslen = len;
if (len === 0) return resolve([]);
let args = Array.prototype.slice.call(promises);
function resolvePromise(index, value) {
if(typeof value === 'object') { // 传入的是否是object
const then = value.then;
if(typeof then === 'function'){
then.call(value, function(val) {
args[index] = { status: 'fulfilled', value: val};
if(--len === 0) {
resolve(args);
}
}, function(e) {
args[index] = { status: 'rejected', reason: e };
if(--len === 0) {
reject(args);
}
})
}
}
}
for(let i = 0; i < argslen; i++){
resolvePromise(i, args[i]);
}
})
}
тестовое задание
Базовый тест
// 测试
const promise = new NewPromise(function(resolve, reject) {
console.log('ss', 11);
resolve(123);
})
thenтестовое задание
promise.then(val => {
console.log('val', val)
})
catchтестовое задание
const promise = new NewPromise(function(resolve, reject) {
console.log('ss', 11);
reject('errr')
})
promise.catch(err => {
console.log('err', err)
})
finallyтестовое задание
const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);
const p = NewPromise.all([resolved, resolved1, rejected]);
p.then((result) => {
console.log('result', result)
}).catch(err => {
console.log('err', err)
}).finally(() => {
console.log('finally')
})
resolveтестовое задание
const resolved = NewPromise.resolve(1);
resolved.then(val => {
console.log('resolved', val)
})
rejectтестовое задание
const rejected = NewPromise.reject(-1);
rejected.catch(val => {
console.log('rejected', val)
})
allтестовое задание
const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);
const p = NewPromise.all([resolved, resolved1, rejected]);
p.then((result) => {
console.log('result', result)
}).catch(err => {
console.log('err', err)
})
allSettledтестовое задание
const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);
const p = NewPromise.allSettled([resolved, resolved1, rejected]);
p.then((result) => {
console.log('result', result)
})
весь код
- Пожалуйста, нажмите, чтобы перейти
GitHubсклад:Обещают рукописную реализацию, переместите палец и дайте элементуStarНу, что ж, спасибо!
Ссылаться на
Руан Ифэн: Начало работы с ECMAScript 6
22 высокочастотных рукописных вопроса и ответа на JavaScript для интервью
- Если это поможет вам, ставьте лайк 👍, ваша поддержка является движущей силой для моего выхода.
Пополнить
правильноPromise.allСомнительный
- проверенный родной
Promise.allметод.
- когда все выполнено
Изменить асинхронный успешный порядок возврата метода all
- Весь приведенный выше код метода был обновлен.
- тестовый пример, спасибоAshoneAпредложенный вопрос.
const promise1 = new Promise(resolve => {
setTimeout(() => {
resolve("promise1");
}, 200);
});
const promise2 = new Promise(resolve => {
setTimeout(() => {
resolve("promise2");
}, 100);
});
NewPromise.all([promise1, promise2]).then(value => {
console.log(value);
});
Promise.all([promise1, promise2]).then(value => {
console.log(value);
});
- предыдущие результаты испытаний. [тестовый адрес](
код sandbox.io/is/musing-rough…)
- Измененные результаты теста.