открытие
PromiseКак интерфейсное асинхронное решение, можно сказать, что оно популярно во всей сети, почти все асинхронные сценарии и даже фреймворки будут присутствовать, напримерVueпакетная обработка и т.д. Сегодня мы будем следитьPromise A+спецификации для полной реализацииPromiseПолная функция, нечего сказать по коду.
Обещание реализации
статус определение статуса
PromiseНастройка представляет собой необратимый конечный автомат, содержащий:
const PENDDING = "PENDDING"; // 初始化pendding状态
const RESOLVED = "RESOLVED"; // 正确完成resolve状态
const REJECTED = "REJECTED"; // 错误完成reject状态
MyPromise
СоздайтеMyPromiseЗначения и состояния, соответствующие функциям класса и инициализациям
class MyPromise {
constructor(executor) {
// 初始化状态status
// 返回值value
// 错误原因reason
this.status = PENDDING;
this.value = undefined;
this.reason = undefined;
// 返回值回调队列和错误回调队列
this.resolves = [];
this.rejects = [];
// 声明resolve函数
const resolve = (value) => {
if (this.status === PENDDING) {
this.status = RESOLVED; // 变更状态为完成状态
this.value = value; // 赋值
// 执行resolves队列
while (this.resolves.length) {
const callback = this.resolves.shift();
callback(value);
}
}
};
// 声明reject函数
const reject = (reason) => {
if (this.statue === PENDDING) {
this.status = REJECTED; // 变更状态为拒绝状态
this.reason = reason; // 赋值
// 执行rejects队列
while (this.rejects.length) {
const callback = this.rejects.shift();
callback(reason);
}
}
};
try{
executor(resolve,reject)
}catch(e){
reject(e)
}
}
}
MyPromise.then
синхронный и асинхронный
class MyPromise {
// ...
then(resolve, reject) {
// 完成状态,推入完成队列
if (this.status === RESOLVED) {
resolve(this.value);
}
// 拒绝状态,推入拒绝队列
if (this.status === REJECTED) {
reject(this.reason);
}
// 异步情况
if (this.status === PENDDING) {
this.resolves.push(resolve);
this.rejects.push(reject);
}
}
// ...
}
// 测试同步任务
const promise = new MyPromise((resolve, reject) => {
resolve('promise sync')
})
promise.then(res => {
console.log(res)
})
// 打印结果
// promise sync
// 测试异步任务
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('promise async)
}, 500)
})
promise.then(res => {
console.log(res)
})
// 打印结果
// promise async
Сценарий спецификации Promise A+
В соответствии со спецификацией Promise A+ метод then возвращает обещание, что позволяет выполнять нисходящую цепочку вызовов. В то же время, по возвращаемому значению предыдущего метода then, его можно прозрачно передать следующему методу then.
// Promise A+
const promise = new Promise((resolve, reject) => {
resolve("first");
});
// 第一种场景:返回常规值
promise
.then((res) => {
console.log(res);
return "second";
})
.then((res) => {
console.log(res);
});
// 打印结果
// first
// second
// 第二种场景:返回promise
promise
.then((res) => {
console.log(res);
return new Promise((resolve) => {
resolve("promise");
});
})
.then((res) => {
console.log(res);
});
// 打印结果
// first
// promise
// 第三种场景:值穿透
promise
.then((res) => {
console.log(res);
return res;
})
.then()
.then((res) => {
console.log(res);
});
// 打印结果
// first
// first
реализовать тогда
Согласно приведенному выше определению спецификации, давайте преобразуемthenметод:
class MyPromise {
// ...
then(resolve, reject) {
// 判断resolve和reject未传入的情况,解决空值透传问题
// then()情况
typeof resolve !== 'function' ? resolve = value => value : resolve
typeof reject !== 'function' ? reject = reason => throw new Error(reason instanceof Error ? reason.message : reason )
//根据规范,then会返回一个全新的promise
return new MyPromise((resolveFn, rejectFn) => {
// 重写传入的resolve方法
// 判断返回值
const fulfilished = value => {
try{
// 接收返回值
const res = resolve(value)
// 判断返回值类型:promise或普通类型
// 如果是promise,则往下执行一次then
// 如果是普通类型,则直接执行resolveFn,保证value是最新值
res instanceof MyPromise ? res.then(resolveFn,rejectFn) : resolveFn(res)
}catch(e) {
rejectFn(e)
}
}
// 重写传入的reject方法
// 判断返回值
const rejected = reason => {
try{
// 接收返回值
const res = reject(reason)
// 判断返回值类型:promise或普通类型
// 如果是promise,则往下执行一次then
// 如果是普通类型,则直接执行rejectFn,保证value是最新值
res instanceof MyPromise ? res.then(resolveFn,rejectFn) : rejectFn(res)
}catch(e){
rejectFn(e instanceof Error ? e.message: e)
}
}
// 判断同步异步任务
// 执行相对应的方法
// 这里用switch方法改进
switch(this.status) {
case RESOLVED:
fulfilished(this.value)
break;
case REJECTED:
rejected(this.reason)
break;
case PENDDING:
this.resolves.push(fulfilished)
this.rejects.push(rejected)
break;
}
})
}
// ...
}
// 测试
const promise = new MyPromise((resolve, reject) => {
resolve('first')
})
promise.then(res => {
console.log(res)
return new MyPromise((resolve, reject) => {
resolve('promise second')
})
}).then().then(res => {
console.log(res)
return 'third'
}).then(res => {
console.log(res)
})
// 打印结果
// first
// promise second
// third
резюме
испытание прошло успешно,promiseДаже если модификация соответствует спецификации. Трудность в том, чтоthenЕсли возвращаемое значение внутренней функции равноpromise, то позволим ему выполнить регистрацию один разthen,ПозволятьpromiseЗатем спускайтесь.
MyPromise.catch
catchМетод относительно прост, поместите отклоненное значение вrejectметод может быть выполнен.
Сценарий спецификации Promise A+
// Promise A+
const promise = new Promise((resolve, reject) => {
reject("promise reject");
});
promise.catch((e) => {
console.log(e);
});
// 打印结果
// promise reject
реализовать улов
class MyPromise {
// ...
catch(errorFn) {
// 这里只需注册执行下then,传入callback就能实现
this.then(null, errorFn);
}
// ...
}
// 测试
const promise = new MyPromise((resolve, reject) => {
reject("my promise reject");
});
promise.catch((e) => {
console.log(e);
});
// 打印结果
// my promise reject
резюме
catchМетод заключается в выполнении обратного вызова для полученияreject, поэтому просто выполнитеthenи пройти вcallbackЭто реализовано, относительно легко понять.
MyPromise.all
В бизнес-сценариях мы часто сталкиваемся с более чем однимpromie, поэтому вам нужно объединить несколько исполнений одновременноpromise, равномерно вернуть результат,Promise.allКак раз для решения этой проблемы.
Сценарий спецификации Promise A+
// Promise A+
// 创建三个promise
const promise1 = Promise.resolve(1)
const promise2 = Promise.resolve(2)
const promise3 = Promise.resolve(3)
Promise.all([promise1,promise12,promise3]).then(res => {
console.log(res)
})
// 打印结果
// [1,2,3]
// 添加一个reject
const promise4 = Promise.resolve(1)
const promise5 = Promise.reject('reject')
const promise6 = Promise.resolve(3)
Promise.all([promise4, promise5,promise6]).then(res => {
console.log(res, 'resolve')
}).catch(e => {
console.log(e)
})
// 打印结果
// reject
Согласно спецификации Promise A+, Promise.all может выполнять несколько промисов одновременно и возвращает возвращаемое значение массива после возврата всех методов промисов. Когда одно из обещаний отклоняется, возвращается результат отклонения.
Реализовать обещание.все
Давайте реализуем это:
class MyPromise {
// ...
// all是静态方法
static all(promises) {
// 已然是返回一个promise
return new MyPromise((resolve, reject) => {
// 创建一个收集返回值的数组
const result = []
// 执行
deepPromise(promises[0], 0 , result)
// 返回结果
resolve(result)
// 这里我们用递归来实现
// @param {MyPromise} promise 每一个promise方法
// @param {number} index 索引
// @param {string[]} result 收集返回结果的数组
function deepPromise(promise, index, result) {
// 边界判断
// 所有执行完之后返回收集数组
if(index > promises.length - 1) {
return result
}
if(typeof promise.then === 'function') {
// 如果是promise
promise.then(res => {
index++
result.push(res)
deepPromise(promises[index], index, result)
}).catch(e => {
// reject直接返回
reject(e instanceof Error ? e.message : e)
})
}else {
// 如果是普通值
// 这里我们只做简单判断,非promise则直接当返回值处理
index++
result.push(promise)
deepPromise(promises[index], index, res)
}
}
})
}
// ...
}
// 测试
// 创建三个MyPromise
const promise1 = MyPromise.resolve(1)
const promise2 = MyPromise.resolve(2)
const promise3 = MyPromise.resolve(3)
MyPromise.all([promise1,promise12,promise3]).then(res => {
console.log(res)
})
// 打印结果
// [1,2,3]
// 添加一个reject
const promise4 = MyPromise.resolve(1)
const promise5 = MyPromise.reject('reject')
const promise6 = MyPromise.resolve(3)
MyPromise.all([promise4, promise5,promise6]).then(res => {
console.log(res, 'resolve')
}).catch(e => {
console.log(e)
})
// 打印结果
// reject
резюме
Promise.allВ качестве функции пакетной обработки мы можем использовать несколько обработок одновременно.promise, что упрощает недостаток выполнения по одному. Основная логика также относительно проста, наиболее важным моментом является выполнениеpromiseперейти к следующемуpromiseПосле обработки этой логики он в основном завершенPromise.allполностью функциональна.
MyPromise.resolve
статический методresolveРеализация относительно проста, возвращаяpromise, вы можете передать соответствующие параметры.
Реализовать MyPromise.resolve
class MyPromise {
// ...
static resolve(value) {
return new MyPromise((resolveFn, rejectFn) => {
resolveFn(value)
})
}
// ...
}
// 测试
MyPromise.resolve('static resolve').then(res => {
console.log(res)
})
// 打印结果
// static resolve
MyPromise.reject
статический методrejectреализация иresolveаналогично, возвращаетpromise, вы можете передать соответствующие параметры.
class MyPromise {
// ...
static reject(reason) {
return new MyPromise((resolveFn, rejectFn) => {
rejectFn(reason)
})
}
// ...
}
// 测试
MyPromise.reject('static reject').catch(e => {
console.log(res)
})
// 打印结果
// static reject
Что такое allSetted?
Последнее обновление официального сайта ECMAPromiseновый статический методPromise.allSettled, то что это за метод? А вообще он тоже пакетная обработкаPromiseфункцию, но у нас уже естьPromise.allЗачем тебе нужноallSettled. Чтобы разгадать это, мы должны оглянуться назадPromise.all. токPromise.allМы сказали, что еслиPromiseЕсть один в очередиreject, то он просто возвращаетсяreject,такPromise.allНе обязательно все результаты будут возвращены, очевидноPromise.allSettledможет решить эту проблему.
Сценарий тестирования Promise A+
// Promise A+
// 创建三个promise
const promise1 = Promise.resolve(1)
const promise2 = Promise.resolve(2)
const promise3 = Promise.resolve(3)
Promise.allSettled([promise1,promise12,promise3]).then(res => {
console.log(res)
})
// 打印结果
/*
[
{status: 'fulfilished', value: 1},
{status: 'fulfilished', value: 2},
{status: 'fulfilished', value: 3}
]
*/
// 添加一个reject
const promise4 = Promise.resolve(1)
const promise5 = Promise.reject('reject')
const promise6 = Promise.resolve(3)
Promise.allSettled([promise4, promise5,promise6]).then(res => {
console.log(res, 'resolve')
}).catch(e => {
console.log(e)
})
// 打印结果
/*
[
{status: 'fulfilished', value: 1},
{status: 'rejected', value: 'reject'},
{status: 'fulfilished', value: 3}
]
*/
можно увидетьallSettledСамое большое отличие от всех в том, что,allSettledне важно какresolve,ещеrejectможет вернуть результирующий массив полностью, но каждый элемент массива выводится в виде объекта,statusописать состояние,valueПолучите возвращаемое значение.
Реализовать MyPromise.allSettled
allSettledобщая логикаallто же самое, но возвращаемое значение обрабатывается немного по-другому
class MyPromise {
// ...
static allSettled(promises) {
// 已然是返回一个promise
return new MyPromise((resolve, reject) => {
// 创建一个收集返回值的数组
const result = []
// 执行
deepPromise(promises[0], 0 , result)
// 返回结果
resolve(result)
// 这里我们用递归来实现
// @param {MyPromise} promise 每一个promise方法
// @param {number} index 索引
// @param {string[]} result 收集返回结果的数组
function deepPromise(promise, index, result) {
// 边界判断
// 所有执行完之后返回收集数组
if(index > promises.length - 1) {
return result
}
if(typeof promise.then === 'function') {
// 如果是promise
promise.then(res => {
index++
result.push({status: 'fulfilished', value: res}) // 这里推入的是对象
deepPromise(promises[index], index, result)
}).catch(e => {
// reject直接返回
index ++
result.push({status: 'rejected', value: res}) // 这里推入的是对象
deepPromise(promises[index], index, result)
})
}else {
// 如果是普通值
// 这里我们只做简单判断,非promise则直接当返回值处理
index++
result.push({status: 'fulfilished', value: res}) // 这里推入的是对象
deepPromise(promises[index], index, res)
}
}
})
}
// ...
}
// 测试
// 创建三个promise
const promise1 = MyPromise.resolve(1)
const promise2 = MyPromise.resolve(2)
const promise3 = MyPromise.resolve(3)
MyPromise.allSettled([promise1,promise12,promise3]).then(res => {
console.log(res)
})
// 打印结果
/*
[
{status: 'fulfilished', value: 1},
{status: 'fulfilished', value: 2},
{status: 'fulfilished', value: 3}
]
*/
// 添加一个reject
const promise4 = MyPromise.resolve(1)
const promise5 = MyPromise.reject('reject')
const promise6 = MyPromise.resolve(3)
Promise.allSettled([promise4, promise5,promise6]).then(res => {
console.log(res, 'resolve')
}).catch(e => {
console.log(e)
})
// 打印结果
/*
[
{status: 'fulfilished', value: 1},
{status: 'rejected', value: 'reject'},
{status: 'fulfilished', value: 3}
]
*/
полный код
class MyPromise {
constructor(executor) {
// 初始化状态status
// 返回值value
// 错误原因reason
this.statue = PENDDING;
this.value = undefined;
this.reason = undefined;
// 返回值回调队列和错误回调队列
this.resolves = [];
this.rejects = [];
// 声明resolve函数
const resolve = (value) => {
if (this.status === PENDDING) {
this.status = RESOLVED; // 变更状态为完成状态
this.value = value; // 赋值
// 执行resolves队列
while (this.resolves.length) {
const callback = this.resolves.shift();
callback(value);
}
}
};
// 声明reject函数
const reject = (reason) => {
if (this.statue === PENDDING) {
this.status = REJECTED; // 变更状态为拒绝状态
this.reason = reason; // 赋值
// 执行rejects队列
while (this.rejects.length) {
const callback = this.rejects.shift();
callback(reason);
}
}
};
try{
executor(resolve,reject)
}catch(e){
reject(e)
}
}
// then
then(resolve, reject) {
// 判断resolve和reject未传入的情况,解决空值透传问题
// then()情况
typeof resolve !== 'function' ? resolve = value => value : resolve
typeof reject !== 'function' ? reject = reason => throw new Error(reason instanceof Error ? reason.message : reason): reject
//根据规范,then会返回一个全新的promise
return new MyPromise((resolveFn, rejectFn) => {
// 重写传入的resolve方法
// 判断返回值
const fulfilished = value => {
try{
// 接收返回值
const res = resolve(value)
// 判断返回值类型:promise或普通类型
// 如果是promise,则往下执行一次then
// 如果是普通类型,则直接执行resolveFn,保证value是最新值
res instanceof MyPromise ? MyPromise.then(resolveFn,rejectFn) : resolveFn(res)
}catch(e) {
rejectFn(e)
}
}
// 重写传入的reject方法
// 判断返回值
const rejected = reason => {
try{
// 接收返回值
const res = reject(reason)
// 判断返回值类型:promise或普通类型
// 如果是promise,则往下执行一次then
// 如果是普通类型,则直接执行rejectFn,保证value是最新值
res instanceof MyPromise ? MyPromise.then(resolveFn,rejectFn) : rejectFn(res)
}catch(e){
rejectFn(e instanceof Error ? e.message: e)
}
}
// 判断同步异步任务
// 执行相对应的方法
// 这里用switch方法改进
switch(this.status) {
case RESOLVED:
fulfilished(this.value)
break;
case REJECTED:
rejected(this.reason)
break;
case PENDDING:
this.resolves.push(fulfilished)
this.rejects.push(rejected)
break;
}
})
}
catch(errorFn) {
// 这里只需注册执行下then,传入callback就能实现
this.then(null, errorFn);
}
// resolve
static resolve(value) {
return new MyPromise((resolveFn, rejectFn) => {
resolveFn(value)
})
}
// reject
static reject(reason) {
return new MyPromise((resolveFn, rejectFn) => {
rejectFn(reason)
})
}
// all
static all(promises) {
// 已然是返回一个promise
return new MyPromise((resolve, reject) => {
// 创建一个收集返回值的数组
const result = []
// 执行
deepPromise(promises[0], 0 , result)
// 返回结果
resolve(result)
// 这里我们用递归来实现
// @param {MyPromise} promise 每一个promise方法
// @param {number} index 索引
// @param {string[]} result 收集返回结果的数组
function deepPromise(promise, index, result) {
// 边界判断
// 所有执行完之后返回收集数组
if(index > promises.length - 1) {
return result
}
if(typeof promise.then === 'function') {
// 如果是promise
promise.then(res => {
index++
result.push(res)
deepPromise(promises[index], index, result)
}).catch(e => {
// reject直接返回
reject(e instanceof Error ? e.message : e)
})
}else {
// 如果是普通值
// 这里我们只做简单判断,非promise则直接当返回值处理
index++
result.push(promise)
deepPromise(promises[index], index, res)
}
}
})
}
// allSettled
static allSettled(promises) {
// 已然是返回一个promise
return new MyPromise((resolve, reject) => {
// 创建一个收集返回值的数组
const result = []
// 执行
deepPromise(promises[0], 0 , result)
// 返回结果
resolve(result)
// 这里我们用递归来实现
// @param {MyPromise} promise 每一个promise方法
// @param {number} index 索引
// @param {string[]} result 收集返回结果的数组
function deepPromise(promise, index, result) {
// 边界判断
// 所有执行完之后返回收集数组
if(index > promises.length - 1) {
return result
}
if(typeof promise.then === 'function') {
// 如果是promise
promise.then(res => {
index++
result.push({status: 'fulfilished', value: res}) // 这里推入的是对象
deepPromise(promises[index], index, result)
}).catch(e => {
// reject直接返回
index ++
result.push({status: 'rejected', value: res}) // 这里推入的是对象
deepPromise(promises[index], index, result)
})
}else {
// 如果是普通值
// 这里我们只做简单判断,非promise则直接当返回值处理
index++
result.push({status: 'fulfilished', value: res}) // 这里推入的是对象
deepPromise(promises[index], index, res)
}
}
})
}
}
Суммировать
слишком далекоPromise A+Полный метод и реализацияpromiseТрудность заключается в пониманииthenКак быть с прозрачной передачей значения , если вы понимаете этот момент, другие методы и логика будут более естественными Если у вас есть какие-либо вопросы, вы можете указать в комментариях.