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
What's the yield keyword in JavaScript?
提问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
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()

