Что такое обещание? В жизни вы можете сказать, что это гарантия. Однако как вы опишете это в Javascript?

В Javascript обещание - это решение для асинхронного программирования. Синтаксически обещание - это конструктор. Объект обещания инкапсулирует асинхронную операцию и получает ее успешный или неудачный результат.

До появления Обещания. Как разработчик javascript мы будем использовать обратный вызов для обработки асинхронной операции. Итак, что такое обратный вызов? Я бы сказал, что обратный вызов - это функция, которая требует времени для получения результата для асинхронной операции. Асинхронное программирование обычно представляет собой файловые операции fs, операции с базой данных, AJAX и setTimeout. Например, если нам нужно прочитать файл с помощью операции fs, а функция обратного вызова в операции чтения файла также должна вызвать операцию чтения файла, тогда новейшая функция обратного вызова также должна вызвать операцию чтения файла. Следовательно, будет выглядеть

require('fs').readFile('./a.html',(err, data)=>{
     require('fs').readFile('./b.html',(err, data)=>{
          require('fs').readFile('./c.html',(err, data)=>{})
     })
})

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

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

В Promise состояние инициализации отложено. После того, как Promise получит результат, ожидание инициализации изменится на разрешенное (если получено успешное завершение) или отклоненное (если получено неудачное). Мы будем использовать метод then (), чтобы выявить окончательный результат. Promise изменит свое состояние только один раз, независимо от того, не работает оно или нет. Успешные данные называются значением, данные об ошибках - причиной. Теперь давайте посмотрим на один пример, чтобы увидеть, как рабочий процесс для Promise

//First, we create a Promise, and the state is pending now.
const promise = new Promise((resolve, reject) => {
//Second, asynchronous task is executing
  setTimeout(()=>{
       const n=Math.ceil(Math.random()*10)
      //Third, there are two possibility, if n >5, we call resolve()
      //to set the value, the Promise change state to resolved. If        
      //n<=5, we call reject() to set the reason, Promise change 
      //state to rejected
      if (n > 5) {
           resolve(n + " is larger than 5 ")
       } else {
           reject(n + " isn't larger than 5 ")
       }
   },1000)
})
//Four, then() to handle the result, value is successful result.
//Reason is failure result.
promise.then(
   value => {console.log(value)},
   reason => {console.log(reason)}
)

Мы ознакомились с рабочим процессом Promise, а теперь давайте познакомимся с некоторыми API-интерфейсами Promise, отличными от then ().

catch () - это метод, который возвращает обещание, но обещание было отклонено. Promise может использовать серию вызовов then () как цепочку, и мы можем добавить только один catch () в хвост цепочки для обработки отклонения. Если какой-либо шаг после then () был отклонен в цепочке обещаний, catch () будет вызван для отклонения.

//If we want to add up the content of a.txt three time
//Using callback
//we can see that, we have to hadle the error for each readFile()
fs.readFile('./a.txt', 'utf8', (err, data) => {
   if(err) console.log(err)
   fs.readFile('./a.txt', 'utf8', (err, newData) => {
     if(err) console.log(err)
     fs.readFile('./a.txt', 'utf8',(err, newestData) => {
       if (err) console.log(err)
       console.log(data+newData+newestData)
     })
   })
})
//Using Promise
//We only need to add catch once in the chain tail for exception //handing
fs.promises.readFile('./a.txt', 'utf8').then(value1 =>
   fs.promises.readFile('./a.txt', 'utf8').then(value2 => 
      fs.promises.readFile('./a.txt', 'utf8').then(value3 =>
         console.log(value1+value2+value3)
      )
    )
).catch(error => console.error(error))

После того, как мы изучим catch (), мы сможем построить график рабочего процесса Promise, как показано ниже.

resolve () - это метод, который возвращает обработанное обещание с заданным значением или разрешенное / отклоненное обещание.

//Returning resolved Promise with a given value
Promise.resolve('resolved Promise with a given value').then(  
  value=>console.log(value)
  ).catch( 
    reason=>consolw.log(reason)
  )
//Returning a resolved Promise
Promise.resolve(Promise.resolve('a resolved Promise')).then(
   value=>console.log(value)
  ).catch(
    reason=>consolw.log(reason)
  )
//Returning a rejected Promise
Promise.resolve(Promise.reject('a rejected Promise')).then(
   value=>console.log(value)
  ).catch( 
    reason=>console.log(reason) 
  )

reject () - это метод, который возвращает отклоненное обещание.

//Returning a reason for rejected
Promise.reject('Reason for rejected').then(
   value=>console.log(value)
).catch(
  reason=>console.log(reason)
)

all () - это метод, возвращающий новое обещание. Если все обещания разрешены, верните разрешенное обещание, в противном случае верните отклоненное обещание. Мы можем использовать пример с readFile () с использованием обратного вызова, который мы использовали ранее, чтобы увидеть, как мы используем all (), чтобы избежать ада обратного вызова.

const p1 = fs.promises.readFile('./a.txt', 'utf8')
const p2 = fs.promises.readFile('./a.txt', 'utf8')
const p3 = fs.promises.readFile('./a.txt', 'utf8')
//Pushing p1,p2 and p3 to a array as a parameter
//The return value also array 
Promise.all([p1, p2, p3]).then(
   ([value1, value2, value3]) => 
    console.log(value1 + value2 + value3)
).catch(reason => console.error(reason))

race () - это метод, который возвращает новое обещание, результирующее состояние первого выполненного обещания является конечным состоянием результата. Если первое выполненное обещание отклоняется, обещание отклоняется.

const p1 = fs.promises.readFile('./a.txt', 'utf8')
const p2 = fs.promises.readFile('./a.txt', 'utf8')
const p3 = fs.promises.readFile('./a.txt', 'utf8')
//Pushing p1,p2 and p3 to a array as a parameter
Promise.race([p1, p2, p3]).then(
    value=> console.log(value)
).catch(reason => console.error(reason))

Теперь мы, вероятно, знаем основы использования и синтаксис Promise. Однако, когда мы занимаемся реальной разработкой, у нас действительно есть более элегантный способ использования Promise. То есть использовать асинхронную функцию и выражение ожидания.

async - ключевое слово для функции. Возвращаемое значение асинхронной функции - объект обещания. Результат объекта Promise определяется возвращаемым значением выполнения асинхронной функции.

const fn = async () => {
     const p1 = fs.promises.readFile('./a.txt', 'utf8')
     return p1
}
fn().then(
    (value) => console.log(value)
).catch(
    (reason)=>console.log(reason)
)

Из приведенного выше примера мы видим, что асинхронная функция возвращает обещание, но нам все равно нужно использовать then () для возвращаемого значения, чтобы перевести состояние ожидания в состояние выполнения. Теперь позвольте мне представить, как опустить then (). То есть использовать ожидание.

ожидание - ключевое слово выражения. Обычно он используется слева от выражений Promise (или других выражений). Если выражение является обещанием, ожидание возвращает значение разрешения обещания. Если выражение является другим выражением, верните значение выражения. ожидание необходимо внутри функции async. Однако, как и в приведенном выше примере, асинхронная функция не обязательно должна иметь внутри await. Кроме того, await возвращает только разрешенное значение для Promise, если значение Promise отклонено, await выдаст исключение. Поэтому лучше использовать trt {} catch () для выражения с ключевым словом await.

const fn = async () => { 
  try {
      const p1 = await fs.promises.readFile('./a.txt', 'utf8')
      const p2 = await fs.promises.readFile('./a.txt', 'utf8') 
      const p3 = await fs.promises.readFile('./a.txt', 'utf8')
      console.log(p1 + p2 + p3)
  } catch (error) {
     console.log(error)
  }
}
fn()

Заключение

В разработке нам часто требуется использовать Promise. Например, при разработке интерфейса мы часто запрашиваем данные из серверной части или серверной части, поскольку node.js запрашивает данные из базы данных асинхронно. Поэтому мы будем использовать для них Promise. Надеюсь, эта статья будет полезна для тех, кто изучает Promise. Если вы хотите использовать Promise более гибко, вам может потребоваться более глубокое понимание синхронного / асинхронного программирования и четного цикла javascript. Я также буду публиковать статьи на эти темы в будущем. Надеюсь, вам понравится моя статья.