aguardar, assíncrono, loop de eventos (tarefa macro, sequência de execução da fila de micro tarefas)

1 assíncrono, aguardar

2 Processos e threads do navegador

3 Macro tarefas e filas de microtarefas

4 Análise das perguntas da entrevista Promise

5 lançar, tentar, pegar, finalmente

Função assíncrona - Como escrever uma função assíncrona

 // 普通函数
    // function foo() {}
    // const bar = function() {}
    // const baz = () => {}

    // 生成器函数
    // function* foo() {}

    // 异步函数
    async function foo() {
      console.log("foo function1")
      console.log("foo function2")
      console.log("foo function3")
    }
    foo()

    // const bar = async function() {}
    // const baz = async () => {}
    // class Person {
    //   async running() {}
    // }

Valor de retorno da função assíncrona - função assíncrona

// 返回值的区别
    // 1.普通函数
    // function foo1() {
    //   return 123
    // }
    // foo1()

    // 2.异步函数
    async function foo2() {
      // 1.返回一个普通的值
      // -> Promise.resolve(321)
      return ["abc", "cba", "nba"]

      // 2.返回一个Promise
      // return new Promise((resolve, reject) => {
      //   setTimeout(() => {
      //     resolve("aaa")
      //   }, 3000)
      // })

      // 3.返回一个thenable对象
      // return {
      //   then: function(resolve, reject) {
      //     resolve("bbb")
      //   }
      // }
    }

    foo2().then(res => {
      console.log("res:", res)
    })

Funções assíncronas – Exceções em funções assíncronas

Se houver erros ou exceções no código assíncrono, isso não afetará o código subsequente, mas os resultados serão passados ​​na rejeição da promessa.

 // "abc".filter()

    // 什么情况下异步函数的结果是rejected

    // 如果异步函数中有抛出异常(产生了错误), 这个异常不会被立即浏览器处理
    // 进行如下处理: Promise.reject(error)
    async function foo() {
      console.log("---------1")
      console.log("---------2")
      // "abc".filter()
      throw new Error("coderwhy async function error")
      console.log("---------3")

      // return new Promise((resolve, reject) => {
      //   reject("err rejected")
      // })

      return 123
    }

    // promise -> pending -> fulfilled/rejected
    foo().then(res => {
      console.log("res:", res)
    }).catch(err => {
      console.log("coderwhy err:", err)
      console.log("继续执行其他的逻辑代码")
    })

Uso de palavra-chave assíncrona de espera de função

Se await for usado simplesmente em variáveis ​​​​e funções comuns, é inútil. É usado em conjunto com a promessa. Sua função é semelhante ao rendimento. É esperar até que a promessa retorne antes de receber o resultado e então executar as seguintes linhas de espera. (Isso interromperá a execução do código).

// 1.普通函数
    // function foo1() {
    //   await 123
    // }
    // foo1()


    // 2.await关键字
    // await条件: 必须在异步函数中使用
    function bar() {
      console.log("bar function")
      return new Promise(resolve => {
        setTimeout(() => {
          resolve(123)
        }, 100000)
      })
    }

    async function foo() {
      console.log("-------")
      // await后续返回一个Promise, 那么会等待Promise有结果之后, 才会继续执行后续的代码
      const res1 = await bar()
      console.log("await后面的代码:", res1)
      const res2 = await bar()
      console.log("await后面的代码:", res2)

      console.log("+++++++")
    }

    foo()

Função assíncrona-await lida com solicitações assíncronas

Quando a promessa retorna rejeitada, o catch pode ser usado para capturar exceções e erros. Ou escreva try catch em getdata.

 function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(url)
          // reject("error message")
        }, 2000);
      })
    }

    async function getData() {
      const res1 = await requestData("why")
      console.log("res1:", res1)

      const res2 = await requestData(res1 + "kobe")
      console.log("res2:", res2)
    }

    getData().catch(err => {
      console.log("err:", err)
    })

Função assíncrona – combinação de await e async

Funções comuns retornam promessas, mas funções criadas com a palavra-chave assíncrona async também podem usar await ao chamar.

  // 1.定义一些其他的异步函数
    function requestData(url) {
      console.log("request data")
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(url)
        }, 3000)
      })
    }

    async function test() {
      console.log("test function")
      return "test"
    }

    async function bar() {
      console.log("bar function")

      return new Promise((resolve) => {
        setTimeout(() => {
          resolve("bar")
        }, 2000);
      })
    }

    async function demo() {
      console.log("demo function")
      return {
        then: function(resolve) {
          resolve("demo")
        }
      }
    }


    // 2.调用的入口async函数
    async function foo() {
      console.log("foo function")

      const res1 = await requestData("why")
      console.log("res1:", res1)

      const res2 = await test()
      console.log("res2:", res2)

      const res3 = await bar()
      console.log("res3:", res3)

      const res4 = await demo()
      console.log("res4:", res4)
    }

    foo()

Thread único - como a sequência de código é executada

Cada página aberta pelo navegador se tornará um processo. Haverá muitos threads em um processo, mas haverá apenas um thread que executa JavaScript.

 let name = "why"
    name = "kobe"

    function bar() {
      console.log("bar function")
    }

    function foo() {
      console.log("foo function")
      // 1.在JavaScript内部执行
      // let total = 0
      // for (let i = 0; i < 1000000; i++) {
      //   total += i
      // }

      // 2.创建一个定时器
      setTimeout(() => {
        console.log("setTimeout")
      }, 10000);

      bar()
    }

    foo()

Thread único - como o código assíncrono é executado

Independentemente do tempo definido pelo cronômetro, o código por trás do cronômetro será executado primeiro.

 Fila de eventos, loop de eventos.

Timers, monitores DOM e solicitações de rede serão todos adicionados à fila de eventos e, em seguida, a fila de eventos insere eventos no contexto de execução em uma ordem de primeiro a entrar, primeiro a sair.

 

<body>

  <button>按钮</button>
  
  <script>

    const btn = document.querySelector("button")
    btn.onclick = function() {
      console.log("btn click event")
    }

    console.log("Hello World")
    let message = "aaaa"
    message = "bbbb"

    setTimeout(() => {
      console.log("10s后的setTimeout")
    }, 0);

    console.log("Hello JavaScript")
    console.log("代码继续执行~~~")
    console.log("-------------")

  </script>

</body>

Single thread – a diferença entre microtarefas e macrotarefas

As funções dentro da promessa são iguais às funções escritas fora. Elas são executadas imediatamente e não são colocadas na fila de eventos. Mas se esta promessa executar resolver ou rejeitar, o código na função de retorno de chamada then e catch será colocado na fila.

O código do cronômetro será colocado na macrotarefa, e o código então será colocado na microtarefa.

A divisão entre tarefas macro e micro tarefas é estipulada e não escolhida por nós.

 

A função das microtarefas é executar antes das macrotarefas, portanto, as microtarefas são executadas antes das macrotarefas.

  console.log("script start")

    // function bar() {
    //   console.log("bar function")
    // }

    // function foo() {
    //   console.log("foo function")
    //   bar()
    // }
    // foo()

    // 定时器
    setTimeout(() => {
      console.log("setTimeout0")
    }, 0)
    setTimeout(() => {
      console.log("setTimeout1")
    }, 0)

    // Promise中的then的回调也会被添加到队列中
    console.log("1111111")
    new Promise((resolve, reject) => {
      console.log("2222222")
      console.log("-------1")
      console.log("-------2")
      resolve()
      console.log("-------3")
    }).then(res => {
      console.log("then传入的回调: res", res)
    })
    console.log("3333333")

    console.log("script end")

Sequência de execução de código – pergunta 1 da entrevista (importante)

Observe que funções comuns e funções de retorno de chamada de promessa são executadas diretamente no contexto de execução, e o código então e a captura dos retornos de chamada de resolução e rejeição da promessa são executados em microtarefas.

Microtarefas são executadas antes das macrotarefas

A melhor maneira é desenhar a ordem de execução da fila de tarefas macro e da fila de micro tarefas

 

 Se houver microtarefas na microtarefa, a macrotarefa será adiada até a execução, independentemente de a microtarefa ter sido concluída antecipadamente. Se você criar uma microtarefa ao executar uma macrotarefa (a macrotarefa já foi executada, só se pode dizer que a microtarefa terminou), após a conclusão da macrotarefa, você voltará imediatamente para executar a microtarefa .

 Sequência final de execução:

 

 console.log("script start")

    setTimeout(function () {
      console.log("setTimeout1");
      new Promise(function (resolve) {
        resolve();
      }).then(function () {
        new Promise(function (resolve) {
          resolve();
        }).then(function () {
          console.log("then4");
        });
        console.log("then2");
      });
    });

    new Promise(function (resolve) {
      console.log("promise1");
      resolve();
    }).then(function () {
      console.log("then1");
    });

    setTimeout(function () {
      console.log("setTimeout2");
    });

    console.log(2);

    queueMicrotask(() => {
      console.log("queueMicrotask1")
    });

    new Promise(function (resolve) {
      resolve();
    }).then(function () {
      console.log("then3");
    });

    console.log("script end")

Ordem de execução do código - aguardar código

Se then for executado em uma tarefa macro, a tarefa macro que a envolve será executada primeiro e depois a microtarefa.

O cronômetro também é dividido em tarefas macro avançadas de tempo curto.

 Antes de await obter o resultado, o código subsequente neste escopo não será executado e será ignorado. E o código por trás do await no mesmo escopo é equivalente ao código do then, que é colocado em microtarefas.

 

 console.log("script start")

    function requestData(url) {
      console.log("requestData")
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log("setTimeout")
          resolve(url)
        }, 2000);
      })
    }

    // 2.await/async
    async function getData() {
      console.log("getData start")
      const res = await requestData("why")
      
      console.log("then1-res:", res)
      console.log("getData end")
    }

    getData()
    
    console.log("script end")

    // script start
    // getData start
    // requestData
    // script end

    // setTimeout

    // then1-res: why
    // getData end

Pergunta 2 da entrevista sobre sequência de execução de código

Quando o async2() for executado na figura abaixo, a função asunc2 será chamada. Embora apenas async2 seja impresso, há um retorno oculto indefinido, que é equivalente a resolve(indefinido), e a linha console.log('async1 end') will É adicionado à microtarefa porque equivale a ser colocado em then .

 Nota: O código de await async2() será executado como código normal como console.log('async1 start'), enquanto await async2() é uma função. Você precisa encontrar essa função e então pular para esta função para executar o código dentro.

 

 

  async function async1 () {
      console.log('async1 start')
      await async2();
      console.log('async1 end')
    }

    async function async2 () {
      console.log('async2')
    }

    console.log('script start')

    setTimeout(function () {
      console.log('setTimeout')
    }, 0)
    
    async1();
    
    new Promise (function (resolve) {
      console.log('promise1')
      resolve();
    }).then (function () {
      console.log('promise2')
    })

    console.log('script end')

Tratamento de exceções - tratamento de erros padrão

Se o navegador relatar um erro, o código após a linha do código-fonte do erro não será executado. Então é perigoso.

Uma das soluções é lançar ativamente uma exceção, usando a palavra-chave throw. Mas o código por trás do throw também não será executado, a vantagem é que você pode lançar a descrição personalizada do seu problema.

 

 // 1.遇到一个错误, 造成后续的代码全部不能执行
    // function foo() {
    //   "abc".filter()

    //   console.log("第15行代码")
    //   console.log("-------")
    // }

    // foo()
    // console.log("+++++++++")

    // const btn = document.querySelector("button")
    // btn.onclick = function() {
    //   console.log("监听btn的点击")
    // }

    // 2.自己封装一些工具
    function sum(num1, num2) {
      if (typeof num1 !== "number") {
        throw "type error: num1传入的类型有问题, 必须是number类型"
      }

      if (typeof num2 !== "number") {
        throw "type error: num2传入的类型有问题, 必须是number类型"
      }

      return num1 + num2
    }

    // 李四调用
    const result = sum(123, 321)

O lançamento de tratamento de exceção lança uma exceção

Se a informação da exceção lançada for uma frase, ela não terá efeito. Geralmente, o tipo de objeto é usado para lançá-la e o conteúdo que pode ser exibido é maior. Claro, você também pode personalizar a classe para escrever mensagens de erro.

O sistema também possui classes de erro escritas que podem ser usadas diretamente. 

  class HYError {
      constructor(message, code) {
        this.errMessage = message
        this.errCode = code
      }
    }

    // throw抛出一个异常
    // 1.函数中的代码遇到throw之后, 后续的代码都不会执行
    // 2.throw抛出一个具体的错误信息
    function foo() {
      console.log("foo function1")
      // 1.number/string/boolean
      // throw "反正就是一个错误"

      // 2.抛出一个对象
      // throw { errMessage: "我是错误信息", errCode: -1001 }
      // throw new HYError("错误信息", -1001)

      // 3.Error类: 错误函数的调用栈以及位置信息
      throw new Error("我是错误信息")

      console.log("foo function2")
      console.log("foo function3")
      console.log("foo function4")
    }

    function bar() {
      foo()
    }

    bar()

 

Tratamento de exceções - como capturar exceções

Por que o código subsequente não é executado quando ocorre um erro?

Isso ocorre porque o erro é relatado camada por camada a partir do local onde o erro é relatado, e um erro eventualmente será lançado no navegador, de modo que a execução do código subsequente será interrompida. Se escrevermos outro código para capturar e manipular o erro, o código subsequente pode continuar a ser executado.

finalmente será definitivamente executado

 function foo() {
      console.log("foo function1")
      // throw new Error("我是错误信息")
      console.log("foo function2")
      console.log("foo function3")
      console.log("foo function4")
    }

    function test() {
      // 自己捕获了异常的话, 那么异常就不会传递给浏览器, 那么后续的代码可以正常执行
      try {
        foo()
        console.log("try后续的代码")
      } catch(error) {
        console.log("catch中的代码")
        // console.log(error)
      } finally {
        console.log("finally代码")
      }
    }

    function bar() {
      test()
    }

    bar()

    console.log("--------")

Depois de escrever o resultado de try catch para capturar a exceção, o código subsequente pode ser executado normalmente.

 

Acho que você gosta

Origin blog.csdn.net/weixin_56663198/article/details/131728637
Recomendado
Clasificación