Обещание должен знать должен знать (десять вопросов)

JavaScript Promise

Промисы должны быть хорошо знакомы всем, подумайте всего лишь о нескольких API, но действительно ли вы понимаете промисы? В этой статье собраны десять вопросов, основанных на некоторых знаниях о Promise, и вы увидите, сколько из них вы можете ответить правильно.

Все следующие промисы относятся к экземплярам промисов, а среда — Node.js.

тема один

const promise = new Promise((resolve, reject) => {
  console.log(1)
  resolve()
  console.log(2)
})
promise.then(() => {
  console.log(3)
})
console.log(4)

результат операции:

1
2
4
3

Объяснение: Конструктор Promise выполняется синхронно,promise.thenФункции в выполняются асинхронно.

тема вторая

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
const promise2 = promise1.then(() => {
  throw new Error('error!!!')
})

console.log('promise1', promise1)
console.log('promise2', promise2)

setTimeout(() => {
  console.log('promise1', promise1)
  console.log('promise2', promise2)
}, 2000)

результат операции:

promise1 Promise { <pending> }
promise2 Promise { <pending> }
(node:50928) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: error!!!
(node:50928) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
promise1 Promise { 'success' }
promise2 Promise {
  <rejected> Error: error!!!
    at promise.then (...)
    at <anonymous> }

Объяснение: Обещание имеет 3 состояния: ожидание, выполнено или отклонено. Изменение состояния может быть только ожидающим->выполненным или ожидающим->отклоненным.После изменения состояния его нельзя изменить снова. Вышеприведенный promise2 не является promise1, а возвращается новый экземпляр Promise.

тема три

const promise = new Promise((resolve, reject) => {
  resolve('success1')
  reject('error')
  resolve('success2')
})

promise
  .then((res) => {
    console.log('then: ', res)
  })
  .catch((err) => {
    console.log('catch: ', err)
  })

результат операции:

then: success1

Объяснение: разрешить или отклонить в конструкторе допустимо только для первого выполнения, а множественные вызовы не имеют никакого эффекта, повторяя вывод кода 2: как только состояние промиса изменилось, его нельзя изменить снова.

тема четвертая

Promise.resolve(1)
  .then((res) => {
    console.log(res)
    return 2
  })
  .catch((err) => {
    return 3
  })
  .then((res) => {
    console.log(res)
  })

результат операции:

1
2

Объяснение: Обещания могут быть связаны. Когда дело доходит до цепочки вызовов, мы обычно думаем о передачеreturn thisРеализовано, но обещания не реализованы таким образом. обещание вызывается каждый раз.thenили.catchвернет новое обещание, тем самым реализуя связанные вызовы.

пятая тема

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('once')
    resolve('success')
  }, 1000)
})

const start = Date.now()
promise.then((res) => {
  console.log(res, Date.now() - start)
})
promise.then((res) => {
  console.log(res, Date.now() - start)
})

результат операции:

once
success 1005
success 1007

Объяснение: Обещание.thenили.catchМожет вызываться несколько раз, но здесь конструктор Promise выполняется только один раз. Другими словами, как только внутреннее состояние обещания изменится и получит значение, каждый последующий вызов.thenили.catchполучит значение напрямую.

тема шесть

Promise.resolve()
  .then(() => {
    return new Error('error!!!')
  })
  .then((res) => {
    console.log('then: ', res)
  })
  .catch((err) => {
    console.log('catch: ', err)
  })

результат операции:

then: Error: error!!!
    at Promise.resolve.then (...)
    at ...

объяснять:.thenили.catchВозврат объекта ошибки не приводит к ошибке, поэтому он не будет использоваться последующими.catchCapture, необходимо изменить на одно из следующих:

return Promise.reject(new Error('error!!!'))
throw new Error('error!!!')

Поскольку возврат любого значения, не являющегося обещанием, будет заключен в объект обещания, то естьreturn new Error('error!!!')Эквивалентноreturn Promise.resolve(new Error('error!!!')).

тема семь

const promise = Promise.resolve()
  .then(() => {
    return promise
  })
promise.catch(console.error)

результат операции:

TypeError: Chaining cycle detected for promise #<Promise>
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
    at Function.Module.runMain (module.js:667:11)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:607:3

объяснять:.thenили.catchВозвращаемое значение не может быть самим промисом, иначе это вызовет бесконечный цикл. Похожий на:

process.nextTick(function tick () {
  console.log('tick')
  process.nextTick(tick)
})

тема восьмая

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)

результат операции:

1

объяснять:.thenили.catchОжидается, что параметр будет функцией, и если будет передана не функция, произойдет проникновение значения.

тема девять

Promise.resolve()
  .then(function success (res) {
    throw new Error('error')
  }, function fail1 (e) {
    console.error('fail1: ', e)
  })
  .catch(function fail2 (e) {
    console.error('fail2: ', e)
  })

результат операции:

fail2: Error: error
    at success (...)
    at ...

объяснять:.thenМожет принимать два параметра: первый — это функция для обработки успеха, а второй — функция для обработки ошибок..catchда.thenСокращение для второго параметра, но есть предостережение по их использованию:.thenВторая функция обработки ошибок не перехватывает ошибки, выдаваемые первой успешной функцией обработки, и последующими..catchМожет поймать предыдущие ошибки. Конечно, следующий код также работает:

Promise.resolve()
  .then(function success1 (res) {
    throw new Error('error')
  }, function fail1 (e) {
    console.error('fail1: ', e)
  })
  .then(function success2 (res) {
  }, function fail2 (e) {
    console.error('fail2: ', e)
  })

тема десятая

process.nextTick(() => {
  console.log('nextTick')
})
Promise.resolve()
  .then(() => {
    console.log('then')
  })
setImmediate(() => {
  console.log('setImmediate')
})
console.log('end')

результат операции:

end
nextTick
then
setImmediate

объяснять:process.nextTickиpromise.thenВсе относятся к микрозадачам, иsetImmediateПринадлежит макрозадаче и выполняется на этапе проверки цикла обработки событий. Микрозадача выполняется между каждым этапом цикла событий (макрозадача), а микрозадача выполняется первой в начале цикла событий.


Автором этой статьи является графитовый документnswbmwодноклассник.