Потому что я не могу понять Promise.all, интервью холодно

интервью внешний интерфейс JavaScript
Потому что я не могу понять Promise.all, интервью холодно

предисловие

(ಥ﹏ಥ) Реальный случай, который произошел с другом, интервьюер попросил его написатьPromise.all, мой друг не очень хорошо сыграл на месте, поэтому не записал, а потом попросил интервьюера дать расплывчатую оценку:Фундамент недостаточно прочный, и основные знания менее усвоены...Конечно, провалилось все интервью, не только эта тема, должны быть и другие причины.

Но это дало нам тревожный звонок:Promise手写实现,Promise静态方法实现Это уже был высокочастотный контрольный вопрос на собеседовании, если вы мало в этом разбираетесь, мы задержим вас на 10 минут.пока он не пойметО (∩_∩) О

Обычный почерк для интервью

胖头鱼Я действительно хочу сделать одну вещь в последнее время, я надеюсь, что смогу рассказать об этом на предварительном собеседовании.常见的手写题Запишите его в серию и постарайтесь ясно объяснить знания и принципы, связанные с ним.Если вам также интересна эта серия, пожалуйста, приходите и учитесь вместе.66+手写题Это сделано!

1. Нажмите, чтобы просмотреть исходный адрес одного вопроса Rigong (в настоящее время реализовано более 66 рукописных вопросов)

2. Столбец самородков

image.png

Promise.resolve

Краткий обзор

  1. Promise.resolve(value) Метод возвращает проанализированный с заданным значениемPromiseобъект.

  2. Если значением является обещание, то будет возвращено это обещание;

  3. Если значение доступно (т. е. с"then" метод), возвращенное обещание будет "следовать" за объектом thenable, принимая его конечное состояние; в противном случае возвращенное обещание будет завершено с этим значением.

Это объяснение на MDN, давайте посмотрим по порядку

  1. Promise.resolveКонечный результат все равноPromise, и сPromise.resolve(该值)Входящее значение тесно связано

  2. Входящий параметр может бытьPromise实例, то результатом выполнения функции является прямой возврат экземпляра

  3. Тут главное понятьследить, можно понимать как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"
  }
]
*/

можно увидеть:

  1. Будь то успех или какая-то неудача, в конечном итоге она войдет вPromise.allSettledиз.thenОбратный вызов

  2. В окончательном возвращаемом значении есть как успешные, так и неудачные элементы.statusсвойство, значение успеха равноfulfilled, который терпит неудачу, когдаrejected

  3. В конечном возвращаемом значении успех содержит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
})

конец

Может быть, мы с тобой никогда не встречались, но очень вероятно, что мы встретимся поздно. надеятьсяздесьМожет стать вашей средой обитания, я хотел бы собирать радость с вами и идти расти.

Это первый рукописный анализ принципа реализации! Добро пожаловать, чтобы исправить любые ошибки и проблемы, которые могут существовать