[Учебник Xiaobai] Обратный вызов Javascript и Promise/async/await

вставьте сюда описание изображения

1. Изначально

Все начинается с того, что Javascript — это язык асинхронного программирования, например самый простой:

  let n = 0
  function f1() {
    
    
    setTimeout(function () {
    
    
      n++
    }, 1000)
  }

  f1()
  console.log(n)

Вы можете интуитивно почувствовать, что n=1 в конце, но на самом деле вывести 0, потому что, хотя функция f1 вызывается, основной процесс не ждет истечения срока действия своего внутреннего таймера, прежде чем продолжить выполнение, а сразу console.log(n). и n=0 в это время.


2. Схема обратного вызова (функции обратного вызова)

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

  let n = 0
  function f1(function_name) {
    
    
    setTimeout(() => {
    
    
      n++
      function_name(n);
    }, 1000);
  }

  function f2 (ret) {
    
    
    console.log(ret)
  }

  f1(f2)

На этот раз выводится значение n = 1. Функция f1 имеет дополнительный параметр имя_функции. Этот параметр сообщает f1, что, когда функция завершит выполнение, возвращаемое значение будет выполнено через функцию имя_функции. Это обратный вызов, то есть, так называемая «функция обратного вызова (callback function)».

  • Анонимная функция
    При вызове callback-функции можно не указывать имя функции, а встраивать тело функции прямо в формальный параметр, или приведенный выше пример можно написать так:
  let n = 0
  function f1(function_name) {
    
    
    setTimeout(() => {
    
    
      n++
      function_name(n);
    }, 1000);
  }

  f1(function (ret) {
    
     
    console.log(ret) 
  })

Такой способ записи нетруден для понимания, то есть функция f2 напрямую встроена в список параметров f1.


3. Ад обратного звонка

Хотя функция обратного вызова решает детерминированную проблему возвращаемого значения асинхронного выполнения, если логика программы требует нескольких асинхронных операций, это приведет к классическому «аду обратных вызовов», например:

  let n = 0
  function f1(function_name) {
    
    
    setTimeout(() => {
    
    
      n++
      function_name(n);
    }, 1000);
  }

  const f3 = f2 = f1

  f1(function (ret) {
    
    
    f2(function (ret) {
    
    
      f3(function (ret) {
    
    
        console.log(ret)
      })
    })
  })

Окончательный результат n = 3. В приведенной выше демонстрации записывается только три уровня. На самом деле, в реальной жизни очень распространено более трех уровней логики. Ад обратного вызова снизит читаемость кода и значительно увеличит сложность.


4. Обещанная схема

Promise — это новая функция в ES6, и ее основная цель — решить «адскую» проблему, вызванную «старомодными» функциями обратного вызова. Перепишите приведенный выше пример следующим образом:

  let n = 0
  function f1() {
    
    
    return new Promise((resolve, reject) => {
    
    
      setTimeout(() => {
    
    
        n++
        resolve(n)
      }, 1000);
    })
  }

  const f3 = f2 = f1

  f1()
    .then(() => f2())
    .then(() => f3())
    .then(
      ret => {
    
    
        console.log(ret)
      })

Конечный результат такой же, как и у версии с обратным вызовом, по-прежнему n=3, но запись и понимание намного проще, чем в первом случае, за счет .then()формирования так называемого «цепного вызова», то есть после успешного выполнения предыдущей операции следующий начинает работу.

Есть два момента, на которые необходимо обратить внимание при использовании: во-первых, return new Promise((resolve, reject) => { ... }) обернуть трудоемкую операцию с помощью , а resolve (ret)смысл заключается в том, чтобы нести возвращаемое значение, аналогичное return (ret).

PS: второй параметр reject не используется в приведенном выше примере, и он выдаст сообщение об отказе от выполнения.Например, если мы изменим resolve(n) в приведенном выше примере на reject(n), цепочка вызовов будет прервано, f2 , f3 не будут выполнены. reject обычно используется в связке с механизмом перехвата ошибок catch, конечно, если такого требования нет, reject можно не указывать.

  • Стрелочная функция. В приведенном выше примере
    используется множество =>таких «стрелочных» функций , соответствующих устаревшему functionметоду объявления функций. Ниже приведено сравнение:

  • функция с именем
    без параметров: abc = () => { 函数体 }равно function abc() { 函数体 }
    с параметрами: abc = (v1, v2) => { 函数体 }равноfunction abc(v1, v2) { 函数体 }

  • Анонимная функция
    без параметров: () => { 函数体 }равно function () { 函数体 }
    с параметрами: (v1, v2) => { 函数体 }равно function (v1, v2) { 函数体 }
    PS: Если имеется только одна переменная, круглые скобки не требуются, например:

  abc = v1 => {
    
    
    console.log(v1)
  }

Или как в примере выше:

  ret => {
    
    
    console.log(ret)
  }

Пять, асинхронно и ждать

С помощью async и await вы можете писать код, который больше похож на «синхронный» язык программирования, например:

  let n = 0
  function f1() {
    
    
    return new Promise((resolve) => {
    
    
      setTimeout(() => {
    
    
        n++
        resolve(n)
      }, 1000);
    })
  }

  const f3 = f2 = f1

  async function run() {
    
    
    await f1()
    console.log(n)
    await f2()
    console.log(n)
    await f3()
    console.log(n)
  }

  run()

Обратите внимание, что схема async/wait не может быть вызвана непосредственно на самом внешнем уровне основной программы, но должна указывать «функцию выполнения» и добавлять ключевое слово перед ней, в этом примере и в теле функции asyncвыполнения async function run() , Добавьте ключевое слово перед вызываемой функцией await, что означает, что функция будет выполняться синхронно.В приведенном выше примере перед f1, f2 и f3 добавляется await, что означает, что эти три функции выполняются один за другим. один в порядке. Представьте, что в исходном примере Javascript этот код должен выводить сразу 3 0, а не выводить 1-секундные интервалы, как сейчас: 1, 2, 3. Этот опыт на самом деле очень близок к синхронному языку программирования.


постскриптум

В этой статье лишь немного рассказывается о механизме асинхронного выполнения, функции обратного вызова, механизме промисов и стрелочной функции Javascript, что является лишь введением. Цель этой статьи состоит не в том, чтобы подробно обсудить эти точки знаний, а в том, чтобы позволить учащимся, которые совершенно незнакомы с ними, как можно скорее «испытать» и получить некоторое перцептивное понимание этого содержания. обратитесь к следующим ссылкам:

Обещание:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arrow_functions

https://juejin.cn/post/7108187709076111367

https://juejin.cn/post/7235177983312216125

Supongo que te gusta

Origin blog.csdn.net/rockage/article/details/131016870
Recomendado
Clasificación