Qual é a palavra-chave yield em JavaScript?

Ouvi falar de uma palavra-chave “yield” em JavaScript, mas encontrei documentação muito pobre sobre isso. Alguém pode me explicar (ou recomendar um site que explica) seu uso e para que é usado?

    A documentação do MDN é muito boa, IMO.

    A function que contém a palavra-chave yield é um gerador. Quando você o chama, seus parâmetros formais estão vinculados a argumentos reais, mas seu corpo não é realmente avaliado. Em vez disso, um gerador-iterador é retornado. Cada chamada ao método next () do gerador-iterador realiza outra passagem pelo algoritmo iterativo. O valor de cada etapa é o valor especificado pela palavra-chave yield. Pense no rendimento como a versão de retorno do gerador-iterador, indicando o limite entre cada iteração do algoritmo. Cada vez que você chama next (), o código do gerador é retomado da instrução após o rendimento.

    Resposta tardia, provavelmente todo mundo sabe sobre o yield agora, mas alguma documentação melhor veio junto.

    Adaptando um exemplo de “Javascript’s Future: Generators” por James Long para o padrão oficial Harmony:

     function * foo(x) { while (true) { x = x * 2; yield x; } } 

    “Quando você chama foo, você recebe um object Generator que tem um próximo método.”

     var g = foo(2); g.next(); // -> 4 g.next(); // -> 8 g.next(); // -> 16 

    Então o yield é como return : você recebe algo de volta. return x retorna o valor de x , mas yield x retorna uma function, que lhe dá um método para iterar para o próximo valor. Útil se você tiver um procedimento potencialmente intensivo de memory que você pode querer interromper durante a iteração.

    Simplificando / elaborando a resposta de Nick Sotiros (o que eu acho incrível), eu acho que é melhor descrever como alguém poderia começar a codificar com yield .

    Na minha opinião, a maior vantagem de usar o yield é que ele eliminará todos os problemas de retorno de chamada nesteds que vemos no código. É difícil ver como, a princípio, decidi escrever essa resposta (para mim e espero que outros!)

    A maneira como o faz é introduzindo a idéia de uma co-rotina, que é uma function que pode parar / pausar voluntariamente até conseguir o que precisa. Em javascript, isso é denotado por function* . Apenas function* function podem usar yield .

    Aqui está um javascript típico:

     loadFromDB('query', function (err, result) { // Do something with the result or handle the error }) 

    Isso é desajeitado porque agora todo o seu código (que obviamente precisa esperar por essa chamada loadFromDB ) precisa estar dentro desse retorno de chamada feio. Isso é ruim por algumas razões …

    • Todo o seu código é recuado em um nível
    • Você tem esse fim }) que você precisa acompanhar em todos os lugares
    • Todo esse jargão extra de function (err, result)
    • Não está exatamente claro que você está fazendo isso para atribuir um valor ao result

    Por outro lado, com yield , tudo isso pode ser feito em uma linha com a ajuda da estrutura agradável de co-rotina.

     function* main() { var result = yield loadFromDB('query') } 

    E agora sua function principal renderá quando necessário, quando precisar esperar por variables ​​e coisas para carregar. Mas agora, para executar isso, você precisa chamar uma function normal (sem co-rotina). Um framework de co-rotina simples pode corrigir esse problema para que tudo que você tenha que fazer seja executar isto:

     start(main()) 

    E o começo é definido (da resposta de Nick Sotiro)

     function start(routine, data) { result = routine.next(data); if(!result.done) { result.value(function(err, data) { if(err) routine.throw(err); // continue next iteration of routine with an exception else start(routine, data); // continue next iteration of routine normally }); } } 

    E agora, você pode ter um código bonito que é muito mais legível, fácil de apagar e não precisa mexer com recuos, funções, etc.

    Uma observação interessante é que, neste exemplo, o yield é, na verdade, apenas uma palavra-chave que você pode colocar antes de uma function com um retorno de chamada.

     function* main() { console.log(yield function(cb) { cb(null, "Hello World") }) } 

    Imprimiria “Olá mundo”. Assim, você pode transformar qualquer function de retorno de chamada em yield simplesmente criando a mesma assinatura de function (sem o cb) e retornando a function (cb) {} , da seguinte forma:

     function yieldAsyncFunc(arg1, arg2) { return function (cb) { realAsyncFunc(arg1, arg2, cb) } } 

    Espero que com esse conhecimento você possa escrever um código mais limpo e legível que seja fácil de excluir !

    É realmente simples, é assim que funciona

    • yield palavra-chave yield simplesmente ajuda a pausar e retomar uma function a qualquer momento de forma assíncrona .
    • Além disso, ajuda a retornar o valor de uma function geradora .

    Tome esta function simples de gerador :

     function* process() { console.log('Start process 1'); console.log('Pause process2 until call next()'); yield; console.log('Resumed process2'); console.log('Pause process3 until call next()'); yield; console.log('Resumed process3'); console.log('End of the process function'); } 

    let _process = process ();

    Até que você chame o _process.next () ele não executará as duas primeiras linhas de código, então o primeiro rendimento irá pausar a function. Para retomar a function até o próximo ponto de pausa ( palavra-chave yield ) você precisa chamar _process.next () .

    Você pode pensar que vários rendimentos são os pontos de interrupção em um depurador de javascript dentro de uma única function. Até que você diga para navegar no próximo ponto de interrupção, ele não executará o bloco de código. ( Nota : sem bloquear toda a aplicação)

    Mas enquanto yield realiza esta pausa e retoma comportamentos, ela pode retornar alguns resultados também {value: any, done: boolean} acordo com a function anterior, não emitimos nenhum valor. Se explorarmos a saída anterior, ela mostrará o mesmo { value: undefined, done: false } com o valor undefined .

    Vamos nos aprofundar na palavra-chave yield. Opcionalmente, você pode adicionar expressão e definir um valor opcional padrão . (Sintaxe doc oficial)

     [rv] = yield [expression]; 

    expressão : Valor para retornar da function geradora

     yield any; yield {age: 12}; 

    rv : Retorna o valor opcional que passou para o método next () do gerador

     let val = yield 99; _process.next(10); now the val will be 10 

    Tente agora

    Usos

    • Avaliação preguiçoso
    • Seqüências infinitas
    • Fluxos de controle asynchronous

    Referências:

    É usado para geradores de iteradores. Basicamente, ele permite que você faça uma sequência (potencialmente infinita) usando código procedural. Veja a documentação do Mozilla .

    Para dar uma resposta completa: o yield está funcionando similar ao return , mas em um gerador.

    Quanto ao exemplo comumente dado, isso funciona da seguinte maneira:

     function *squareGen(x) { var i; for (i = 0; i < x; i++) { yield i*i; } } var gen = squareGen(3); console.log(gen.next().value); // prints 0 console.log(gen.next().value); // prints 1 console.log(gen.next().value); // prints 4 

    Mas há também um segundo propósito da palavra-chave yield. Pode ser usado para enviar valores para o gerador.

    Para esclarecer, um pequeno exemplo:

     function *sendStuff() { y = yield (0); yield y*y; } var gen = sendStuff(); console.log(gen.next().value); // prints 0 console.log(gen.next(2).value); // prints 4 

    Isso funciona, pois o valor 2 é atribuído a y , enviando-o ao gerador, depois que ele parou no primeiro rendimento (que retornou 0 ).

    Isto permite-nos algumas coisas realmente funky. (procure a co-rotina)

    yield também pode ser usado para eliminar callback hell, com uma estrutura de co-rotina.

     function start(routine, data) { result = routine.next(data); if(!result.done) { result.value(function(err, data) { if(err) routine.throw(err); // continue next iteration of routine with an exception else start(routine, data); // continue next iteration of routine normally }); } } // with nodejs as 'node --harmony' fs = require('fs'); function read(path) { return function(callback) { fs.readFile(path, {encoding:'utf8'}, callback); }; } function* routine() { text = yield read('/path/to/some/file.txt'); console.log(text); } // with mdn javascript 1.7 http.get = function(url) { return function(callback) { // make xhr request object, // use callback(null, resonseText) on status 200, // or callback(responseText) on status 500 }; }; function* routine() { text = yield http.get('/path/to/some/file.txt'); console.log(text); } // invoked as.., on both mdn and nodejs start(routine()); 

    Gerador de seqüência de Fibonacci usando a palavra-chave yield.

     function* fibbonaci(){ var a = -1, b = 1, c; while(1){ c = a + b; a = b; b = c; yield c; } } var fibonacciGenerator = fibbonaci(); fibonacciGenerator.next().value; // 0 fibonacciGenerator.next().value; // 1 fibonacciGenerator.next().value; // 1 fibonacciGenerator.next().value; // 2