предисловие
(ಥ﹏ಥ) Реальный случай, который произошел с другом, интервьюер попросил его написатьPromise.all
, мой друг не очень хорошо сыграл на месте, поэтому не записал, а потом попросил интервьюера дать расплывчатую оценку:Фундамент недостаточно прочный, и основные знания менее усвоены...Конечно, провалилось все интервью, не только эта тема, должны быть и другие причины.
Но это дало нам тревожный звонок:Promise手写实现
,Promise静态方法实现
Это уже был высокочастотный контрольный вопрос на собеседовании, если вы мало в этом разбираетесь, мы задержим вас на 10 минут.пока он не пойметО (∩_∩) О
Обычный почерк для интервью
胖头鱼
Я действительно хочу сделать одну вещь в последнее время, я надеюсь, что смогу рассказать об этом на предварительном собеседовании.常见的手写题
Запишите его в серию и постарайтесь ясно объяснить знания и принципы, связанные с ним.Если вам также интересна эта серия, пожалуйста, приходите и учитесь вместе.66+手写题
Это сделано!
Promise.resolve
Краткий обзор
-
Promise.resolve(value)
Метод возвращает проанализированный с заданным значениемPromise
объект. -
Если значением является обещание, то будет возвращено это обещание;
-
Если значение доступно (т. е. с
"then"
метод), возвращенное обещание будет "следовать" за объектом thenable, принимая его конечное состояние; в противном случае возвращенное обещание будет завершено с этим значением.
Это объяснение на MDN, давайте посмотрим по порядку
-
Promise.resolve
Конечный результат все равноPromise
, и сPromise.resolve(该值)
Входящее значение тесно связано -
Входящий параметр может быть
Promise实例
, то результатом выполнения функции является прямой возврат экземпляра -
Тут главное понятьследить, можно понимать как
Promise最终状态
является выходом этого тогда доступного объектаценность
небольшой пример
// 1. 非Promise对象,非thenable对象
Promise.resolve(1).then(console.log) // 1
// 2. Promise对象成功状态
const p2 = new Promise((resolve) => resolve(2))
Promise.resolve(p2).then(console.log) // 2
// 3. Promise对象失败状态
const p3 = new Promise((_, reject) => reject('err3'))
Promise.resolve(p3).catch(console.error) // err3
// 4. thenable对象
const p4 = {
then (resolve) {
setTimeout(() => resolve(4), 1000)
}
}
Promise.resolve(p4).then(console.log) // 4
// 5. 啥都没传
Promise.resolve().then(console.log) // undefined
реализация исходного кода
Promise.myResolve = function (value) {
// 是Promise实例,直接返回即可
if (value && typeof value === 'object' && (value instanceof Promise)) {
return value
}
// 否则其他情况一律再通过Promise包装一下
return new Promise((resolve) => {
resolve(value)
})
}
// 测试一下,还是用刚才的例子
// 1. 非Promise对象,非thenable对象
Promise.myResolve(1).then(console.log) // 1
// 2. Promise对象成功状态
const p2 = new Promise((resolve) => resolve(2))
Promise.myResolve(p2).then(console.log) // 2
// 3. Promise对象失败状态
const p3 = new Promise((_, reject) => reject('err3'))
Promise.myResolve(p3).catch(console.error) // err3
// 4. thenable对象
const p4 = {
then (resolve) {
setTimeout(() => resolve(4), 1000)
}
}
Promise.myResolve(p4).then(console.log) // 4
// 5. 啥都没传
Promise.myResolve().then(console.log) // undefined
сомневаться
Из реализации исходного кода я не увидел, что дляthenable
Особое обращение с объектами! На самом деле, вам не нужноPromise.resolve
обработка, реальное место обработки должно быть вPromise
В конструкторе, если вам интересна эта штука, вы сразу напишетеPromise
Реализация статьи, с нетерпением жду вашего чтения О.
Promise.reject
Краткий обзор
Promise.reject()
Метод возвращаетPromise
объект.
Promise.reject(new Error('fail'))
.then(() => console.log('Resolved'),
(err) => console.log('Rejected', err))
// 输出以下内容
// Rejected Error: fail
// at <anonymous>:2:16
реализация исходного кода
Реализация reject относительно проста, пока возвращается новое обещание, а статус результата установлен на reject.
Promise.myReject = function (value) {
return new Promise((_, reject) => {
reject(value)
})
}
// 测试一下
Promise.myReject(new Error('fail'))
.then(() => console.log('Resolved'),
(err) => console.log('Rejected', err))
// Rejected Error: fail
// at <anonymous>:9:18
Promise.all
Краткий обзор
Promise.all()
Этот метод используется для переноса нескольких экземпляров Promise в новый экземпляр Promise.Этот статический метод должен быть наиболее распространенным в интервью.
const p = Promise.all([p1, p2, p3])
наконец-тоp
статус поp1
,p2
,p3
Решение разделено на два случая.
(1) толькоp1
,p2
,p3
статус сталfulfilled
,p
государство станетfulfilled
,В настоящее времяp1
,p2
,p3
Возвращаемые значения образуют массив, который передается вp
функция обратного вызова.
(2) покаp1
,p2
,p3
один из них былrejected
,p
состояние становитсяrejected
, в это время первыйreject
Возвращаемое значение экземпляра , будет передано вp
функция обратного вызова.
const p1 = Promise.resolve(1)
const p2 = new Promise((resolve) => {
setTimeout(() => resolve(2), 1000)
})
const p3 = new Promise((resolve) => {
setTimeout(() => resolve(3), 3000)
})
const p4 = Promise.reject('err4')
const p5 = Promise.reject('err5')
// 1. 所有的Promise都成功了
const p11 = Promise.all([ p1, p2, p3 ])
.then(console.log) // [ 1, 2, 3 ]
.catch(console.log)
// 2. 有一个Promise失败了
const p12 = Promise.all([ p1, p2, p4 ])
.then(console.log)
.catch(console.log) // err4
// 3. 有两个Promise失败了,可以看到最终输出的是err4,第一个失败的返回值
const p13 = Promise.all([ p1, p4, p5 ])
.then(console.log)
.catch(console.log) // err4
реализация исходного кода
Promise.myAll = (promises) => {
return new Promise((rs, rj) => {
// 计数器
let count = 0
// 存放结果
let result = []
const len = promises.length
if (len === 0) {
return rs([])
}
promises.forEach((p, i) => {
// 注意有的数组项有可能不是Promise,需要手动转化一下
Promise.resolve(p).then((res) => {
count += 1
// 收集每个Promise的返回值
result[ i ] = res
// 当所有的Promise都成功了,那么将返回的Promise结果设置为result
if (count === len) {
rs(result)
}
// 监听数组项中的Promise catch只要有一个失败,那么我们自己返回的Promise也会失败
}).catch(rj)
})
})
}
// 测试一下
const p1 = Promise.resolve(1)
const p2 = new Promise((resolve) => {
setTimeout(() => resolve(2), 1000)
})
const p3 = new Promise((resolve) => {
setTimeout(() => resolve(3), 3000)
})
const p4 = Promise.reject('err4')
const p5 = Promise.reject('err5')
// 1. 所有的Promise都成功了
const p11 = Promise.myAll([ p1, p2, p3 ])
.then(console.log) // [ 1, 2, 3 ]
.catch(console.log)
// 2. 有一个Promise失败了
const p12 = Promise.myAll([ p1, p2, p4 ])
.then(console.log)
.catch(console.log) // err4
// 3. 有两个Promise失败了,可以看到最终输出的是err4,第一个失败的返回值
const p13 = Promise.myAll([ p1, p4, p5 ])
.then(console.log)
.catch(console.log) // err4
// 与原生的Promise.all返回是一致的
Promise.allSettled
Краткий обзор
Иногда мы хотим дождаться завершения набора асинхронных операций, независимо от того, была ли каждая операция успешной или неудачной, прежде чем перейти к следующему шагу. очевидно
Promise.all
(Пока это отказ, результатом является состояние отказа) Это не подходит, поэтому естьPromise.allSettled
Promise.allSettled()
Метод принимает массив в качестве параметра, каждый член массива является объектом Promise и возвращает новый объект Promise. Подождите только, пока все объекты Promise массива параметров изменят свое состояние (будь тоfulfilled
все ещеrejected
), состояние возвращенного объекта Promise изменится.fulfilled
, не станетrejected
Взяв приведенный выше пример в качестве примера, давайте посмотрим наPromise.all
какая разница
const p1 = Promise.resolve(1)
const p2 = new Promise((resolve) => {
setTimeout(() => resolve(2), 1000)
})
const p3 = new Promise((resolve) => {
setTimeout(() => resolve(3), 3000)
})
const p4 = Promise.reject('err4')
const p5 = Promise.reject('err5')
// 1. 所有的Promise都成功了
const p11 = Promise.allSettled([ p1, p2, p3 ])
.then((res) => console.log(JSON.stringify(res, null, 2)))
// 输出
/*
[
{
"status": "fulfilled",
"value": 1
},
{
"status": "fulfilled",
"value": 2
},
{
"status": "fulfilled",
"value": 3
}
]
*/
// 2. 有一个Promise失败了
const p12 = Promise.allSettled([ p1, p2, p4 ])
.then((res) => console.log(JSON.stringify(res, null, 2)))
// 输出
/*
[
{
"status": "fulfilled",
"value": 1
},
{
"status": "fulfilled",
"value": 2
},
{
"status": "rejected",
"reason": "err4"
}
]
*/
// 3. 有两个Promise失败了
const p13 = Promise.allSettled([ p1, p4, p5 ])
.then((res) => console.log(JSON.stringify(res, null, 2)))
// 输出
/*
[
{
"status": "fulfilled",
"value": 1
},
{
"status": "rejected",
"reason": "err4"
},
{
"status": "rejected",
"reason": "err5"
}
]
*/
можно увидеть:
-
Будь то успех или какая-то неудача, в конечном итоге она войдет в
Promise.allSettled
из.then
Обратный вызов -
В окончательном возвращаемом значении есть как успешные, так и неудачные элементы.
status
свойство, значение успеха равноfulfilled
, который терпит неудачу, когдаrejected
-
В конечном возвращаемом значении успех содержит
value
собственность, в то время как неудачаreason
Атрибуты
реализация исходного кода
Promise.myAllSettled = (promises) => {
return new Promise((rs, rj) => {
let count = 0
let result = []
const len = promises.length
// 数组是空的话,直接返回空数据
if (len === 0) {
return rs([])
}
promises.forEach((p, i) => {
Promise.resolve(p).then((res) => {
count += 1
// 成功属性设置
result[ i ] = {
status: 'fulfilled',
value: res
}
if (count === len) {
rs(result)
}
}).catch((err) => {
count += 1
// 失败属性设置
result[i] = {
status: 'rejected',
reason: err
}
if (count === len) {
rs(result)
}
})
})
})
}
// 测试一下
const p1 = Promise.resolve(1)
const p2 = new Promise((resolve) => {
setTimeout(() => resolve(2), 1000)
})
const p3 = new Promise((resolve) => {
setTimeout(() => resolve(3), 3000)
})
const p4 = Promise.reject('err4')
const p5 = Promise.reject('err5')
// 1. 所有的Promise都成功了
const p11 = Promise.myAllSettled([ p1, p2, p3 ])
.then((res) => console.log(JSON.stringify(res, null, 2)))
// 输出
/*
[
{
"status": "fulfilled",
"value": 1
},
{
"status": "fulfilled",
"value": 2
},
{
"status": "fulfilled",
"value": 3
}
]
*/
// 2. 有一个Promise失败了
const p12 = Promise.myAllSettled([ p1, p2, p4 ])
.then((res) => console.log(JSON.stringify(res, null, 2)))
// 输出
/*
[
{
"status": "fulfilled",
"value": 1
},
{
"status": "fulfilled",
"value": 2
},
{
"status": "rejected",
"reason": "err4"
}
]
*/
// 3. 有两个Promise失败了
const p13 = Promise.myAllSettled([ p1, p4, p5 ])
.then((res) => console.log(JSON.stringify(res, null, 2)))
// 输出
/*
[
{
"status": "fulfilled",
"value": 1
},
{
"status": "rejected",
"reason": "err4"
},
{
"status": "rejected",
"reason": "err5"
}
]
*/
Promise.race
Краткий обзор
Promise.race()
Этот метод также заключается в переносе нескольких экземпляров Promise в новый экземпляр Promise.
const p = Promise.race([p1, p2, p3])
если толькоp1
,p2
,p3
Один из экземпляров первым меняет состояние,p
статус меняется соответственно. Возвращаемое значение экземпляра Promise, который изменился первым, передается вp
функция обратного вызова.
const p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 1)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 2)
})
Promise.race([p1, p2]).then((value) => {
console.log(value) // 2
})
Promise.race([p1, p2, 3]).then((value) => {
console.log(value) // 3
})
реализация исходного кода
Умный, вы должны знать, как это реализовать немедленно, если вы знаете, какой экземпляр изменился первым, а затем
Promise.race
Просто следуйте этому результату, затем вы можете написать следующий код
Promise.myRace = (promises) => {
return new Promise((rs, rj) => {
promises.forEach((p) => {
// 对p进行一次包装,防止非Promise对象
// 并且对齐进行监听,将我们自己返回的Promise的resolve,reject传递给p,哪个先改变状态,我们返回的Promise也将会是什么状态
Promise.resolve(p).then(rs).catch(rj)
})
})
}
// 测试一下
const p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 1)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 2)
})
Promise.myRace([p1, p2]).then((value) => {
console.log(value) // 2
})
Promise.myRace([p1, p2, 3]).then((value) => {
console.log(value) // 3
})
конец
Может быть, мы с тобой никогда не встречались, но очень вероятно, что мы встретимся поздно. надеятьсяздесьМожет стать вашей средой обитания, я хотел бы собирать радость с вами и идти расти.
Это первый рукописный анализ принципа реализации! Добро пожаловать, чтобы исправить любые ошибки и проблемы, которые могут существовать