JavaScript: Funções Generator Assíncronas

A proposta do TC39 de iteradores assíncronos que trouxe for/await/of para o JavaScript também introduziu o conceito de uma função generator assíncrona . Agora, o JavaScript 항목 6 팁 기능 구분:
  • Funções normais function() {}
  • Funções de seta () => {}
  • Funções assíncronas async function() {}
  • Funções de seta assíncrona async () => {}
  • Funções 생성기 function*() {}
  • Funções 발전기 assíncrona async function*() {}

  • As funções generator assíncronas são especiais porque você pode usar ambos await e yield em uma função generator assíncrona. As funções generator assíncrona diferem das funções assíncrona e funções generator porque não retornam uma promessa ou um iterador, mas sim um iterador assíncrono . Você pode pensar em um iterador assíncrono como um iterador onde a função next() semper retorna uma promessa.

    Sua Primeira Função Generator assincrona



    As funções generator assíncronas se comportam de maneira semelhante à as funções generator: a função generator retorna um objeto que tem uma função next() e a chamada next() executa atyield executa 발전기 A diferença é que a função next() de um iterador assíncrono retorna uma promessa .

    Abaixo está um exemplo "Hello, World"com funções generator assíncrona. Node.js anteriores a 10.x의 기능 스크립트를 관찰하십시오.

    'usze strict';
    
    async function* run() {
      // Dorme por 100ms, see: https://masteringjs.io/tutorials/fundamentals/sleep
      await new Promise(resolve => setTimeout(resolve, 100));
      yield 'Hello';
      console.log('World');
    }
    
    // `run()` retorna um iterador assíncrono.
    const asyncIterator = run();
    
    // A função não é executada até `next()` ser chamado
    asyncIterator.next().
      then(obj => console.log(obj.value)). // Prints "Hello"
      then(() => asyncIterator.next());  // Prints "World"
    


    A maneira mais limpa de fazer um loop em todos valores de uma função generator assíncrona é usando um for/await/of .

    'use strict';
    
    async function* run() {
      await new Promise(resolve => setTimeout(resolve, 100));
      yield 'Hello';
      console.log('World');
    }
    
    const asyncIterator = run();
    
    // Imprimi "Hello\nWorld"
    (async () => {
      for await (const val of asyncIterator) {
        console.log(val); // Imprimi "Hello"
      }
    })();
    


    Um caso de uso prático



    Você pode estar pensando "JavaScript precisa de funções 생성기 assíncronas quando já tem funções assíncronas e funções 생성기?"Um caso de uso é o problema classico da barra de progresso em que Ryan Dahl originalmente escreveu Node.js para resolver .

    Suponha que você deseja percorrer todos os documentos em um cursor Mongoose e relatar o progresso via websocket ou para a linha de comando.

    'use strict';
    
    const mongoose = require('mongoose');
    
    async function* run() {
      await mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true });
      await mongoose.connection.dropDatabase();
    
      const Model = mongoose.model('Test', mongoose.Schema({ name: String }));
      for (let i = 0; i < 5; ++i) {
        await Model.create({ name: `doc ${i}` });
      }
    
      // Supondo que você tenha vários documentos e você quer reportar o progresso
      // de cada um. Você pode usar `yield` após processar cada documento.
      const total = 5;
      const cursor = Model.find().cursor();
    
      let processed = 0;
      for await (const doc of cursor) {
        // Você pode pensar em `yield` como reportando: "Finalizei uma unidade de trabalho"
        yield { processed: ++processed, total };
      }
    }
    
    (async () => {
      for await (const val of run()) {
        // Imprimi "1 / 5", "2 / 5", "3 / 5", etc.
        console.log(`${val.processed} / ${val.total}`);
      }
    })();
    


    As funções generator assíncronas tornam mais fácil para sua função assíncrona relatar seu progresso de uma forma sem frameworks . Não há necessidade de criar 명시적 웹소켓 ou log no console - você pode lidar com isso separadamente se assumir que sua lógica de negócios usa yield para relatar seu progresso.

    Com Observáveis



    Os iteradores assíncronos são ótimos, mas há outra primitiva de simultaneidade com a qual as funções generator assíncronas se alinham bem: os observáveis ​​RxJS .

    'use strict';
    
    const { Observable } = require('rxjs');
    const mongoose = require('mongoose');
    
    async function* run() {
      // Mesmo código de antes
    }
    
    // Cria um observável que emite cada valor que o iterador assíncrono retorna
    const observable = Observable.create(async (observer) => {
      for await (const val of run()) {
        observer.next(val);
      }
    });
    
    // Imprimi "1 / 5", "2 / 5", "3 / 5", etc.
    observable.subscribe(val => console.log(`${val.processed} / ${val.total}`));
    


    Existem duas diferenças principais entre usar um observável RxJS e um iterador assíncrono. Primeiro, no exemplo acima, o codigo que se conecta ao console subscribe() é reativo, e não imperativo . Em outras palavras, o manipulador subscribe() não tem como afetar o codigo no corpo da função assíncrona, ele simplesmente reage aos eventos. Ao usar um for/await/of loop, você pode, por exemplo, adicionar uma pausa de 1 segundo antes de retomar a função generator assíncrona.

    (async () => {
      for await (const val of run()) {
        // Imprimi "1 / 5", "2 / 5", "3 / 5", etc.
        console.log(`${val.processed} / ${val.total}`);
        // Adiciona 1 segundo de delay para cada instrução `yield`
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
    })();
    


    A segunda é que, como os observáveis ​​RxJS são frios por padrão , uma nova chamada subscribe() executa novamente a função.

    피날리잔도



    기능 생성기 assíncronas podem parecer de nicho e confusas no início, mas fornecem o que pode se tornar a solução nativa do JavaScript para problemas de "barra de progresso". Usar yield para relatar o progresso de uma função assíncrona é uma ideia atraente porque permite que você desacople sua lógica de negócios de sua estrutura de relatório de progresso. Dê uma 기회 aos generators assíncronos na próxima vez que precisar implementationar uma barra de progresso.


    신용



  • Async Generator Functions in JavaScript, escrito originalmente por .
  • 좋은 웹페이지 즐겨찾기