JavaScript 中的 yield 关键字是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2282140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:36:18  来源:igfitidea点击:

What's the yield keyword in JavaScript?

javascriptyieldkeyword

提问by mck89

I heard about a "yield" keyword in JavaScript, but I found very poor documentation about it. Can someone explain me (or recommend a site that explains) its usage and what it is used for?

我听说过 JavaScript 中的“yield”关键字,但我发现有关它的文档非常糟糕。有人可以解释我(或推荐一个解释的网站)它的用法和用途吗?

采纳答案by Matt Ball

The MDN documentationis pretty good, IMO.

MDN文档是相当不错的,海事组织。

The function containing the yield keyword is a generator. When you call it, its formal parameters are bound to actual arguments, but its body isn't actually evaluated. Instead, a generator-iterator is returned. Each call to the generator-iterator's next() method performs another pass through the iterative algorithm. Each step's value is the value specified by the yield keyword. Think of yield as the generator-iterator version of return, indicating the boundary between each iteration of the algorithm. Each time you call next(), the generator code resumes from the statement following the yield.

包含 yield 关键字的函数是一个生成器。当你调用它时,它的形式参数绑定到实际参数,但它的主体实际上没有被评估。相反,返回一个生成器-迭代器。每次调用生成器-迭代器的 next() 方法都会执行另一次迭代算法。每个步骤的值都是由 yield 关键字指定的值。将 yield 视为 return 的生成器-迭代器版本,指示算法每次迭代之间的边界。每次调用 next() 时,生成器代码都会从 yield 之后的语句恢复。

回答by bishop

Late answering, probably everybody knows about yieldnow, but some better documentation has come along.

迟到的回答,yield现在可能每个人都知道,但一些更好的文档已经出现。

Adapting an example from "Javascript's Future: Generators"by James Long for the official Harmony standard:

将James Long 的“Javascript 的未来:生成器”中的示例改编为官方 Harmony 标准:

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

"When you call foo, you get back a Generator object which has a next method."

“当你调用 foo 时,你会得到一个具有 next 方法的 Generator 对象。”

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

So yieldis kind of like return: you get something back. return xreturns the value of x, but yield xreturns a function, which gives you a method to iterate toward the next value. Useful if you have a potentially memory intensive procedurethat you might want to interrupt during the iteration.

所以yield有点像return:你得到一些回报。 return x返回 的值x,但yield x返回一个函数,该函数为您提供了一个迭代下一个值的方法。如果您有可能需要在迭代期间中断的潜在内存密集型过程,则很有用。

回答by noelyahan

It's Really Simple, This is how it works

这真的很简单,这就是它的工作原理

  • yieldkeyword simply helps to pauseand resumea function in any time asynchronously.
  • Additionally it helps to return valuefrom a generator function.
  • yield关键字只是帮助在任何时间异步暂停恢复功能。
  • 此外,它有助于从生成器函数返回值

Take this simple generatorfunction:

以这个简单的生成器函数为例:

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()');

    let parms = yield {age: 12};
    console.log("Passed by final process next(90): " + parms);

    console.log('Resumed process3');
    console.log('End of the process function');
}

let _process = process();

让 _process = process();

Until you call the _process.next()it wontexecute the first 2 linesof code, then the first yieldwill pausethe function. To resumethe function until next pausepoint (yield keyword) you need to call _process.next().

在您调用_process.next() 之前,不会执行前两行代码,然后第一个 yield暂停该函数。要恢复函数直到下一个暂停点(yield 关键字),您需要调用_process.next()

You can think multiple yieldsare the breakpointsin a javascript debugger within a single function. Until you tell to navigate next breakpoint it wont execute the code block. (Note: without blocking the whole application)

您可以认为多个yield是单个函数内 javascript 调试器中的断点。在您告诉导航下一个断点之前,它不会执行代码块。(注意:不会阻塞整个应用程序)

But while yield performs this pause and resume behaviours it can return some resultsas well {value: any, done: boolean}according to the previous function we haven't emit any values. If we explore the previous output it will show the same { value: undefined, done: false }with value undefined.

但是当 yield 执行这​​个暂停和恢复行为时,它也可以 根据之前的函数返回一些结果{value: any, done: boolean}我们还没有发出任何值。如果我们探索之前的输出,它将显示相同{ value: undefined, done: false }的值undefined

Lets dig in to the yield keyword. Optionally you can add expressionand set assign a default optional value. (Official doc syntax)

让我们深入研究 yield 关键字。您可以选择添加表达式并设置分配默认可选值。(官方文档语法)

[rv] = yield [expression];

expression: Value to return from the generator function

表达式:从生成器函数返回的值

yield any;
yield {age: 12};

rv: Returns the optional value that passed to the generator's next() method

rv: 返回传递给生成器 next() 方法的可选值

Simply you can pass parameters to process() function with this mechanism, to execute different yield parts.

简单地,您可以使用此机制将参数传递给 process() 函数,以执行不同的产量部分。

let val = yield 99; 

_process.next(10);
now the val will be 10 

Try It Now

现在就试试

Usages

用法

  • Lazy evaluation
  • Infinite sequences
  • Asynchronous control flows
  • 懒惰评价
  • 无限序列
  • 异步控制流

References:

参考:

回答by Leander

Simplifying/elaborating on Nick Sotiros' answer (which I think is awesome), I think it's best to describe how one would start coding with yield.

简化/详细阐述 Nick Sotiros 的回答(我认为这很棒),我认为最好描述一个人如何开始使用yield.

In my opinion, the biggest advantage of using yieldis that it will eliminate all the nested callback problems we see in code. It's hard to see how at first, which is why I decided to write this answer (for myself, and hopefully others!)

在我看来,使用的最大好处yield是它会消除我们在代码中看到的所有嵌套回调问题。一开始很难理解,这就是我决定写这个答案的原因(为我自己,也希望其他人!)

The way it does it is by introducing the idea of a co-routine, which is a function that can voluntarily stop/pause until it gets what it needs. In javascript, this is denoted by function*. Only function*functions can use yield.

它的做法是引入协程的概念,协程是一个可以自愿停止/暂停的函数,直到它得到它需要的东西。在 javascript 中,这表示为function*。只有function*函数可以使用yield.

Here's some typical javascript:

这是一些典型的javascript:

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

This is clunky because now all of your code (which obviously needs to wait for this loadFromDBcall) needs to be inside this ugly looking callback. This is bad for a few reasons...

这很笨拙,因为现在你的所有代码(显然需要等待这个loadFromDB调用)都需要在这个丑陋的回调中。这很糟糕,有几个原因......

  • All of your code is indented one level in
  • You have this end })which you need to keep track of everywhere
  • All this extra function (err, result)jargon
  • Not exactly clear that you're doing this to assign a value to result
  • 您的所有代码都缩进一级
  • 你有这个目的}),你需要到处跟踪
  • 所有这些额外的function (err, result)术语
  • 不太清楚你这样做是为了给 result

On the other hand, with yield, all of this can be done in one linewith the help of the nice co-routine framework.

另一方面,有了yield,所有这些都可以在漂亮的协同程序框架的帮助下在一行中完成。

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

And so now your main function will yield where necessary when it needs to wait for variables and things to load. But now, in order to run this, you need to call a normal(non-coroutine function). A simple co-routine framework can fix this problem so that all you have to do is run this:

因此,现在您的主函数将在需要等待变量和事物加载时在必要时产生。但是现在,为了运行它,您需要调用一个普通的(非协程函数)。一个简单的协程框架可以解决这个问题,所以你所要做的就是运行这个:

start(main())

And start is defined (from Nick Sotiro' answer)

并定义了开始(来自 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
        });
    }
}

And now, you can have beautiful code that is much more readable, easy to delete, and no need to fiddle with indents, functions, etc.

现在,您可以拥有更易读、易于删除且无需摆弄缩进、函数等的漂亮代码。

An interesting observation is that in this example, yieldis actually just a keyword you can put before a function with a callback.

一个有趣的观察是,在这个例子中,yield实际上只是一个关键字,你可以放在一个带有回调的函数之前。

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

Would print "Hello World". So you can actually turn any callback function into using yieldby simply creating the same function signature (without the cb) and returning function (cb) {}, like so:

将打印“Hello World”。因此,您实际上可以yield通过简单地创建相同的函数签名(不带 cb)并返回来使用任何回调函数function (cb) {},如下所示:

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

Hopefully with this knowledge you can write cleaner, more readable code that is easy to delete!

希望有了这些知识,您可以编写更清晰、更易读、易于删除的代码!

回答by David

To give a complete answer: yieldis working similar to return, but in a generator.

给出一个完整的答案:yield工作类似于return,但在生成器中。

As for the commonly given example, this works as follows:

对于通常给出的示例,其工作原理如下:

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

But theres also a second purpose of the yield keyword. It can be used to send values to the generator.

但是 yield 关键字还有第二个目的。它可用于将值发送到生成器。

To clarify, a small example:

为了澄清,一个小例子:

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

This works, as the value 2is assigned to y, by sending it to the generator, after it stopped at the first yield (which returned 0).

这是有效的,因为值2被分配给y,通过将它发送到生成器,在它在第一个 yield (返回0)处停止后。

This enables us to to some really funky stuff. (look up coroutine)

这使我们能够做一些非常时髦的事情。(查找协程)

回答by Matthew Flaschen

It's used for iterator-generators. Basically, it allows you to make a (potentially infinite) sequence using procedural code. See Mozilla's documentation.

它用于迭代器生成器。基本上,它允许您使用过程代码创建(可能是无限的)序列。请参阅Mozilla 的文档

回答by Nick Sotiros

yieldcan also be used to eliminate callback hell, with a coroutine framework.

yield也可以用协程框架来消除回调地狱。

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());

回答by nikksan

Fibonacci sequence generator using the yield keyword.

使用 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 

回答by Hanzla Habib

Yeildkeyword in javaScript function makes it generator,

YeildjavaScript 函数中的关键字使其成为生成器,

what is generator in javaScript?

javaScript 中的生成器是什么?

A generator is a function that produces a sequence of results instead of a single value, i.e you generate ?a series of values

生成器是产生一系列结果而不是单个值的函数,即您生成一系列值

Meaning generators helps us work asynchronously with the help iterators, Oh now what the hack iterators are? really?

意义生成器帮助我们与帮助迭代器异步工作,哦,现在黑客迭代器是什么?真的吗?

Iterators are mean through which we are able to access items one at a time

迭代器是平均的,通过它我们可以一次访问一个项目

from where iterator help us accessing item one at a time? it help us accessing items through generator functions,

迭代器从哪里帮助我们一次访问一个项目?它帮助我们通过生成器函数访问项目,

generator functions are those in which we use yeildkeyword, yield keyword help us in pausing and resuming execution of function

生成器函数是我们使用yeild关键字的函数,yield 关键字帮助我们暂停和恢复函数的执行

here is quick example

这是快速示例

function *getMeDrink() {

    let question1 = yield 'soda or beer' // execution will pause here because of yield

 if (question1 == 'soda') {

            return 'here you get your soda'

    }

    if (question1 == 'beer') {

        let question2 = yield 'Whats your age' // execution will pause here because of yield

        if (question2 > 18) {

            return "ok you are eligible for it"

        } else {

            return 'Shhhh!!!!'

        }
    }
}


let _getMeDrink = getMeDrink() // initialize it

_getMeDrink.next().value  // "soda or beer"

_getMeDrink.next('beer').value  // "Whats your age"

_getMeDrink.next('20').value  // "ok you are eligible for it"

_getMeDrink.next().value // undefined

let me brifly explain what is going on

让我简单地解释一下发生了什么

you noticed execution is being paused at each yeildkeyword and we are able to access first yieldwith help of iterator .next()

您注意到每个yeild关键字的执行都被暂停,我们可以yield在迭代器的帮助下首先访问.next()

this iterates to all yieldkeywords one at a time and then returns undefined when there is no more yieldkeywords left in simple words you can say yieldkeyword is break point where function each time pauses and only resume when call it using iterator

这一次迭代到所有yield关键字,然后在没有更多yield关键字时返回 undefined简单的单词你可以说yield关键字是断点,函数每次暂停,只有在使用迭代器调用它时才恢复

for our case: _getMeDrink.next()this is example of iterator that is helping us accessing each break point in function

对于我们的例子:_getMeDrink.next()这是一个迭代器的例子,它帮助我们访问函数中的每个断点

Example of Generators: async/await

生成器示例: async/await

if you see implementation of async/awaityou will see generator functions & promisesare used to make async/awaitwork

如果你看到你的实现,async/await你会看到generator functions & promises被用来制作async/await工作

please point out any suggestions is welcomed

请指出任何建议是受欢迎的

回答by Baltasar Solanilla

Dependency between async javascript calls.

异步 javascript 调用之间的依赖关系。

Another good example of how yield can be used.

如何使用产量的另一个很好的例子。

function request(url) {
  axios.get(url).then((reponse) => {
    it.next(response);
  })
}

function* main() {
  const result1 = yield request('http://some.api.com' );
  const result2 = yield request('http://some.otherapi?id=' + result1.id );
  console.log('Your response is: ' + result2.value);
}

var it = main();
it.next()