предисловие
Один из лучших способов понять что-то состоит в том, чтобы написать это сами, так, вот и поиски. Без дальнейшего ADO давайте посмотрим, как это сделать.
«Пять гор возвращаются, не глядя на горы, и Желтые горы возвращаются, не глядя на горы.» Я надеюсь, что после прочтения этого вам не придется смотреть на принципы реализации других Обещаний.
Обещание разрешения
Первый взглядPromise
Применение:
new Promise((resolve, reject) => {
resolve('hello'); // or reject('hello')
})
.then(res => {})
.catch(err => {})
-----------分割线
// 分解一下,也就是下面这样
let executor = (resolve, reject) => {
resolve('hello'); // or reject('hello')
}
new Promise(executor)
.then(res => {})
.catch(err => {})
Давайте проанализируем, что у него естьФункция/Особенность:
- 1. Два параметра функции (Resolve, Reject) в конструкторе
- 2. Обратный вызов выполняется при успешном разрешении
- 3. Обратный вызов выполняется, когда отклонение не удается
-
4. Три состояния
- ожидание [ожидание] начальное состояние
- выполнено [выполнено] операция выполнена успешно
- отклонено [отклонено] Операция не удалась
- 5, Обещать объектный метод тогда
- 6. Асинхронная реализация
- 7. Асинхронные вызовы onFulfilled и onRejected
- 8. Проникновение ценности
- 9. Перехват метода объекта обещания
- 10. Обещайте все методы объекта
- 11. Гонка методов обещания объекта
- 12. Разрешение метода объекта обещания
- 13. Отклонение метода объекта обещания
- 13. Метод объекта обещания allSettled (последний месяцTC39новые особенности)
Далее нам предстоит один за другим сорвать с него маскировку и раскрыть его истинное лицо.
Реализация базовой структуры Promise
Основываясь на приведенных выше результатах анализа, мы сначала реализуем первые три функции:
- 1. Конструктор передает два параметра функции (разрешить, отклонить)
- 2. Обратный вызов выполняется при успешном разрешении
- 3. Обратный вызов выполняется, когда отклонение не удается
class Promise {
constructor(executor) {
// 定义 resolve
let resolve = res => {}
// 定义 reject
let reject = err => {}
// 自动执行
executor(resolve, reject);
}
}
// 测试一下:
new Promise((resolve, reject) => {
console.log('执行到啦~')
})
Вы можете скопировать приведенный выше код в консоль для выполнения, чтобы увидеть эффект:
Обещание реализации трех состояний
Хорошо, хорошо, теперь давайте реализуем ее три состояния.
-
4. Три состояния
- ожидание [ожидание] начальное состояние
- выполнено [выполнено] операция выполнена успешно
- отклонено [отклонено] Операция не удалась
Состояние обещания имеет следующие характеристики:
1. Состояние инициализации объекта обещания находится на рассмотрении.
2. Когда вызывается разрешение (успех), оно будет выполнено путем ожидания => выполнено
3. Когда вызывается reject (сбой), он будет отклонен путем pending => reject
Статус промиса можно изменить только путем ожидания => выполнено/отклонено, после изменения его нельзя изменить снова
class Promise {
constructor(executor) {
this.status = "pending"; // 默认状态
this.value; // resolve 成功时的值
this.error; // reject 失败时的值
let resolve = res => {
if(this.status === "pending") {
this.value = res;
this.status = "resolved";
}
}
let reject = err => {
if(this.status === "pending") {
this.error = err;
this.status = "rejected";
}
}
executor(resolve, reject);
}
}
1) ожидание [ожидание] начальное состояние
Проверьте это, если вы не идете на решение, не идите на отказ
// 测试一下:
new Promise((resolve, reject) => {
})
Тогда Promise должен быть начальным состоянием. Давайте протестируем приведенный выше код и получим следующие результаты:
{status: "pending"}
.
2) выполнено [осуществлено] Операция прошла успешно
когда мы выполняемresolve
// 测试一下:
new Promise((resolve, reject) => {
resolve('成功啦~');
})
Результат будет следующим:
3) отклоненная [отклоненная] операция не удалась
при исполненииreject
// 测试一下:
new Promise((resolve, reject) => {
resolve('失败啦~')
})
Метод объекта Promise, затем реализация
- 5. Обеспечьте метод объекта, затем
У объекта Promise есть метод then, или нам следует сначала проанализировать, что тогда имеет?
затем принимает два обратных вызова
promise.then(onFulfilled, onRejected); // 这里假设 promise 继承于 Promise 类
Продолжаем писать метод then в предыдущем классе Promise:
class Promise {
constructor(executor) {
this.status = "pending"; // 默认promise状态
this.value; // resolve成功时的值
this.error; // reject失败时的值
let resolve = res => {
if(this.status === "pending") {
this.value = res;
this.status = "resolved";
}
}
let reject = err => {
if(this.status === "pending") {
this.error = err;
this.status = "rejected";
}
}
executor(resolve, reject)
}
// 声明 then
then(onFullfilled, onRejected) {
if(this.status === "resolved") {
onFullfilled(this.value)
}
if(this.status === "rejected") {
onRejected(this.error)
}
}
}
есть тест:
new Promise((resolve, reject) => {
resolve("成功啦~"); // 或 reject("失败啦~")
})
.then(res => {
console.log(res);
}, err => {
console.log(err);
})
получил ответ:
Асинхронная реализация
- 6. Асинхронная реализация
Пока в основном реализуется простой код синхронизации, но когда разрешаетсяsetTimeout
Выполняется внутри, затем состояние все еще находится в состоянии ожидания. Нам нужно сохранить успех и неудачу в их соответствующих массивах, когда вызывается then, и вызывать их после отклонения или разрешения.
похожий наподписка на распространение, сначала сохраните две функции в then.Поскольку промисы могут иметь несколько then, они существуют в одном и том же массиве. Они вызываются с помощью forEach в случае успеха или неудачи.
class Promise {
constructor(executor) {
this.status = "pending"; // 默认promise状态
this.value; // resolve成功时的值
this.error; // reject失败时的值
+ this.resolveQueue = []; // 成功存放的数组
+ this.rejectQueue = []; // 失败存放法数组
let resolve = value => {
if(this.status === "pending") {
this.value = value;
this.status = "resolved";
// 一旦resolve执行,调用成功数组的函数
+ this.resolveQueue.forEach(fn => fn());
}
}
let reject = value => {
if(this.status === "pending") {
this.error = value;
this.status = "rejected";
}
// 一旦reject执行,调用失败数组的函数
+ this.rejectQueue.forEach(fn => fn());
}
executor(resolve, reject)
}
// 执行到then的时候
then(onFullfilled, onRejected) {
if(this.status === "resolved") {
this.resolveQueue.push(() => {
onFullfilled(this.value);
})
}
if(this.status === "rejected") {
this.rejectQueue.push(() => {
onRejected(this.error);
})
}
// 当状态state为pending时
+ if(this.status === "pending") {
// onFulfilled传入到成功数组
+ this.resolveQueue.push(() => {
+ onFullfilled(this.value);
+ })
// onRejected传入到失败数组
+ this.rejectQueue.push(() => {
+ onRejected(this.error);
+ })
+ }
}
}
Цепочка вызовов then
- 7. Цепной вызов потом
мы часто используемnew Promise().then().then()
Этот способ написания, это цепной вызов, который изначально использовался для решения адского обратного вызова. Итак, как этого добиться?
Чтобы добиться этого эффекта, мы можем вернуть еще один из первого, а затем функциюPromise
, пусть это новоеPromise
Возвращенное значение передается следующему then.
Краткое содержание одной фразы:
вернув новый в то время
Promise
, тем самым реализуя цепочку вызовов then!
код показывает, как показано ниже:
class Promise {
constructor(executor) {
this.status = "pending"; // 默认promise状态
this.value; // resolve 成功时的值
this.error; // reject 失败时的值
this.resolveQueue = []; // 成功时回调队列
this.rejectQueue = []; // 失败时回调队列
let resolve = value => {
if(this.status === "pending") {
this.value = value;
this.status = "resolved";
this.resolveQueue.forEach(fn => fn())
}
}
let reject = value => {
if(this.status === "pending") {
this.error = value;
this.status = "rejected";
this.rejectQueue.forEach(fn => fn())
}
}
executor(resolve, reject)
}
then(onFullfilled, onRejected) {
let promise2;
if(this.status === "resolved") {
promise2 = new Promise((resolve, reject) => {
let x = onFullfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
}
if(this.status === "rejected") {
promise2 = new Promise((resolve, reject) => {
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
})
}
if(this.status === "pending") {
promise2 = new Promise((resolve, reject) => {
this.resolveQueue.push(() => {
let x = onFullfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
this.rejectQueue.push(() => {
let x = onRejected(this.error);
resolvePromise(promise2, x, resolve, reject);
})
})
}
return promise2;
}
}
-------------------分割线
// 将上面代码整理一下
class Promise {
constructor(executor) {
this.status = "pending"; // 默认promise状态
this.value; // resolve成功时的值
this.error; // reject失败时的值
this.resolveQueue = []; // 成功时回调队列
this.rejectQueue = []; // 失败时回调队列
let resolve = value => {
if(this.status === "pending") {
this.value = value;
this.status = "resolved";
this.resolveQueue.forEach(fn => fn())
}
}
let reject = value => {
if(this.status === "pending") {
this.error = value;
this.status = "rejected";
this.rejectQueue.forEach(fn => fn())
}
}
executor(resolve, reject)
}
then(onFullfilled, onRejected) {
let promise2;
promise2 = new Promise((resolve, reject) => {
if(this.status === "resolved") {
let x = onFullfilled(this.value);
// resolvePromise函数,处理自己return的promise和默认的promise2的关系
resolvePromise(promise2, x, resolve, reject);
}
if(this.status === "rejected") {
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
}
if(this.status === "pending") {
this.resolveQueue.push(() => {
let x = onFullfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
this.rejectQueue.push(() => {
let x = onRejected(this.error);
resolvePromise(promise2, x, resolve, reject);
})
}
});
// 返回 promise,达成链式效果
return promise2;
}
}
Наконец, давайте завершим приведенную выше функцию resolvePromise, давайте временно сделаем значение, возвращаемое первым, затем x, в этой функции нам нужно определить, является ли x обещанием (вот в чем дело!):
- Да: считать его результат результатом успеха нового обещания2
- нет: непосредственно в результате успеха нового обещания2
Код resolvePromise выглядит следующим образом:
/**
* 处理promise递归的函数
*
* promise2 {Promise} 默认返回的promise
* x {*} 我们自己 return 的对象
* resolve
* reject
*/
function resolvePromise(promise2, x, resolve, reject){
// 循环引用报错
if(x === promise2){
// reject 报错抛出
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 锁,防止多次调用
let called;
// x 不是 null 且 x 是对象或者函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+ 规定,声明then = x的then方法
let then = x.then;
// 如果then是函数,就默认是promise了
if (typeof then === 'function') {
// then 执行 第一个参数是 this 后面是成功的回调 和 失败的回调
then.call(x, y => {
// 成功和失败只能调用一个
if (called) return;
called = true;
// 核心点2:resolve 的结果依旧是 promise 那就继续递归执行
// 核心点2:resolve 的结果依旧是 promise 那就继续递归执行
// 核心点2:resolve 的结果依旧是 promise 那就继续递归执行
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err);// 失败了就失败了
})
} else {
resolve(x); // 直接成功即可
}
} catch (e) { // 走到 catch 也属于失败
if (called) return;
called = true;
// 取then出错了那就不要在继续执行了
reject(e);
}
} else {
resolve(x);
}
}
затем цепочка тестовых вызовов
Полный тестовый код выглядит следующим образом, его можно скопировать в консоль браузера и выполнить:
function resolvePromise(promise2, x, resolve, reject){
// 循环引用报错
if(x === promise2){
// reject 报错抛出
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 锁,防止多次调用
let called;
// x不是null 且x是对象或者函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+ 规定,声明then = x的then方法
let then = x.then;
// 如果then是函数,就默认是promise了
if (typeof then === 'function') {
// 就让then执行 第一个参数是this 后面是成功的回调 和 失败的回调
then.call(x, y => {
// 成功和失败只能调用一个
if (called) return;
called = true;
// resolve的结果依旧是promise 那就继续递归执行
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err);// 失败了就失败了
})
} else {
resolve(x); // 直接成功即可
}
} catch (e) {
// 也属于失败
if (called) return;
called = true;
// 取then出错了那就不要在继续执行了
reject(e);
}
} else {
resolve(x);
}
}
class Promise {
constructor(executor) {
this.status = "pending"; // 默认promise状态
this.value; // resolve成功时的值
this.error; // reject失败时的值
this.resolveQueue = []; // 成功时回调队列
this.rejectQueue = []; // 失败时回调队列
let resolve = value => {
if(this.status === "pending") {
this.value = value;
this.status = "resolved";
this.resolveQueue.forEach(fn => fn())
}
}
let reject = value => {
if(this.status === "pending") {
this.error = value;
this.status = "rejected";
this.rejectQueue.forEach(fn => fn())
}
}
executor(resolve, reject)
}
then(onFullfilled, onRejected) {
let promise2;
promise2 = new Promise((resolve, reject) => {
if(this.status === "resolved") {
let x = onFullfilled(this.value);
// resolvePromise函数,处理自己return的promise和默认的promise2的关系
resolvePromise(promise2, x, resolve, reject);
}
if(this.status === "rejected") {
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
}
if(this.status === "pending") {
this.resolveQueue.push(() => {
let x = onFullfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
this.rejectQueue.push(() => {
let x = onRejected(this.error);
resolvePromise(promise2, x, resolve, reject);
})
}
});
// 返回 promise,达成链式效果
return promise2;
}
}
// 测试以下代码
new Promise((resolve, reject) => {
resolve();
}).then((res)=>{
console.log('进入第一个then!')
return new Promise((resolve,reject)=>{
resolve('hello world');
})
}).then((res)=>{
console.log('进入第二个then!', res);
})
Асинхронные вызовы onFulfilled и onRejected
- 8. Асинхронные вызовы onFulfilled и onRejected
Основная идея:
Решайте асинхронные проблемы с помощью setTimeout
код показывает, как показано ниже:
class Promise {
constructor(executor) {
this.status = "pending"; // 默认promise状态
this.value; // resolve成功时的值
this.error; // reject失败时的值
this.resolveQueue = []; // 成功时回调队列
this.rejectQueue = []; // 失败时回调队列
let resolve = value => {
if(this.status === "pending") {
this.value = value;
this.status = "resolved";
this.resolveQueue.forEach(fn => fn())
}
}
let reject = value => {
if(this.status === "pending") {
this.error = value;
this.status = "rejected";
this.rejectQueue.forEach(fn => fn())
}
}
executor(resolve, reject)
}
then(onFullfilled, onRejected) {
let promise2;
promise2 = new Promise((resolve, reject) => {
if(this.status === "resolved") {
// 异步
+ setTimeout(() => {
let x = onFullfilled(this.value);
// resolvePromise函数,处理自己return的promise和默认的promise2的关系
resolvePromise(promise2, x, resolve, reject);
+ }, 0)
}
if(this.status === "rejected") {
// 异步
+ setTimeout(() => {
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
+ }, 0)
}
if(this.status === "pending") {
this.resolveQueue.push(() => {
// 异步
+ setTimeout(() => {
let x = onFullfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
+ }, 0)
})
this.rejectQueue.push(() => {
// 异步
+ setTimeout(() => {
let x = onRejected(this.error);
resolvePromise(promise2, x, resolve, reject);
+ }, 0)
})
}
});
// 返回 promise,达成链式效果
return promise2;
}
}
вызов проникновения ценности
- 9. Проникновение ценности
new Promise((resolve, reject)=>{
resolve('YoYo');
}).then().then().then().then().then().then().then((res)=>{
console.log(res);
})
При выполнении нескольких then выше мы ожидаем, что последний then напечатает «YoYo».
Реализация проста:Если onFulfilled не является функцией, игнорируйте onFulfilled и возвращайте значение напрямую!
Соответственно, нам также приходится иметь дело со случаем, когда нет onRejected:Если onRejected не является функцией, игнорируйте onRejected и выдавайте ошибку напрямую!
Код выглядит следующим образом, добавленным к then предыдущего класса Promise:
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err;}
<!--... 省略-->
}
Перехват метода объекта обещания
- 10. Перехват метода объекта обещания
Основная идея:
catch — это обратный вызов ошибки, который эквивалентен выполнению this.then(null,fn)
class Promise {
constructor(executor) {
<!--... 省略-->
}
then(onFullfilled, onRejected) {
<!--... 省略-->
}
+ catch(onRejected) {
+ return this.then(null, onRejected)
+ }
}
Кроме того, нам также нужно использовать try/catch для перехвата исключений за пределами нескольких других функций.Это не раскрывается здесь, просто поймите (будет показано в исходном коде в конце этой статьи).
Все методы объекта Promise
- 10. Обещайте все методы объекта
Это классический вопрос для интервью!
Promise.all()
Принимая массив в качестве параметра, метод возвращаетPromise
Экземпляр, что в неразрешенных параметрах для всех обещаний является «полное (разрешенное)» завершение обратного вызова (разрешение) или когда параметр не включает обещание; если параметр обещает ошибка (отклонено), этот экземпляр ошибка обратного вызова (отклоняется), первая причина За провал - это результат неспособности обещания.
Использование заключается в следующем:
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
});
Давайте посмотрим, как это сделать дальше: Далее написано от руки, теста нет, возвращайтесь и добавляйте! После работы ~
Promise.all = function(promises) {
let count = 0;
let res = [];
return new Promise((resolve, reject) => {
for(let i = 0; i<promises.length; i++) {
promises[i].then(res => {
res.push(res);
count++;
if(count === promises.length) resolve(res);
})
}
})
.catch(err => {
reject(err);
})
}
Гонка методов объекта обещания
- 11. Гонка методов обещания объекта
Promise.race() Он также принимает массив объектов-обещаний в качестве параметра и возвращает новый объект-обещание. Как только обещание в итераторе разрешается или отклоняется, возвращенное обещание разрешается или отклоняется.
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
for(let i = 0; i<promises.length; i++) {
promises[i].then(resolve, reject);
}
})
}
Разрешение метода объекта обещания
- 12. Разрешение метода объекта обещания
Promise.resolve = function(value) {
return new Promise((resolve, reject) => {
resolve(value);
})
}
Отклонение метода объекта обещания
- 13. Отклонение метода объекта обещания
Promise.reject = function(value) {
return new Promise((resolve, reject) => {
reject(value);
})
}
Метод объекта обещания allSettled
Давайте сделаем домашнее задание после урока. Учащиеся могут написать сами. Вы можете вернуть их в ответ~
Ссылка:Promises/A+