我听说过JavaScript中的“yield”关键字,但我发现关于它的文档非常糟糕。有人能给我解释一下(或者推荐一个解释它的网站)它的用法和用途吗?
当前回答
在学习yield之前,您需要了解生成器。生成器是使用函数*语法创建的。Generator函数不执行代码,而是返回一种称为Generator的迭代器。当使用下一个方法给出一个值时,生成器函数将继续执行,直到遇到yield关键字。使用yield返回一个包含两个值的对象,一个是value,另一个是done(布尔值)。该值可以是数组、对象等。
其他回答
举个简单的例子:
const strArr = ["red", "green", "blue", "black"];
const strGen = function*() {
for(let str of strArr) {
yield str;
}
};
let gen = strGen();
for (let i = 0; i < 5; i++) {
console.log(gen.next())
}
//prints: {value: "red", done: false} -> 5 times with different colors, if you try it again as below:
console.log(gen.next());
//prints: {value: undefined, done: true}
简化/详细阐述Nick Sotiros的答案(我认为非常棒),我认为最好描述一个人如何开始使用yield编码。
在我看来,使用yield的最大优点是它将消除我们在代码中看到的所有嵌套回调问题。一开始很难理解,这就是为什么我决定写下这个答案(为了我自己,也希望其他人!)
它的方法是通过引入协程的思想,这是一个可以自动停止/暂停的函数,直到它得到它需要的东西。在javascript中,用函数*表示。只有函数*函数可以使用yield。
下面是一些典型的javascript代码:
loadFromDB('query', function (err, result) {
// Do something with the result or handle the error
})
这很笨拙,因为现在所有的代码(显然需要等待loadFromDB调用)都需要在这个丑陋的回调中。这很糟糕,有几个原因……
所有代码都缩进了一层 你有这一端}),你需要随时跟踪 所有这些额外的功能(错误,结果)术语 不太清楚你这样做是为了给result赋值
另一方面,使用yield,所有这些都可以在良好的协同例程框架的帮助下在一行中完成。
function* main() {
var result = yield loadFromDB('query')
}
所以现在你的主函数会在必要的时候让步当它需要等待变量和东西加载时。但是现在,为了运行这个,你需要调用一个普通的(非协程函数)。一个简单的协程框架可以解决这个问题,所以你所要做的就是运行这个:
start(main())
开始是有定义的(来自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
});
}
}
现在,你可以拥有可读性更强、易于删除的漂亮代码,而且不需要修改缩进、函数等。
一个有趣的观察是,在这个例子中,yield实际上只是一个关键字,可以放在带有回调的函数之前。
function* main() {
console.log(yield function(cb) { cb(null, "Hello World") })
}
将打印“Hello World”。因此,你可以通过简单地创建相同的函数签名(不带cb)并返回函数(cb){}来将任何回调函数转换为使用yield,如下所示:
function yieldAsyncFunc(arg1, arg2) {
return function (cb) {
realAsyncFunc(arg1, arg2, cb)
}
}
希望有了这些知识,您可以编写更清晰、更易读且易于删除的代码!
Yield关键字在javaScript函数使它生成器,
什么是JavaScript生成器?
生成器是产生一系列结果而不是单个值的函数,即您生成一系列值
这意味着生成器可以帮助我们与帮助迭代器异步工作,哦,hack迭代器是什么?真的吗?
迭代器意味着我们可以一次访问一个项
从哪里迭代器可以帮助我们一次访问第一项? 它帮助我们通过生成器函数访问项目,生成器函数中我们使用yield关键字,yield关键字帮助我们暂停和恢复函数的执行。
这里有一个简单的例子:
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 'What\'s 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; // "What's your age"
_getMeDrink.next('20').value; // "ok you are eligible for it"
_getMeDrink.next().value; // undefined
让我简单地解释一下发生了什么
你注意到在每个yield关键字处执行被暂停,我们可以通过迭代器.next()访问第一个yield
它一次迭代到所有yield关键字,然后当没有更多的yield关键字时返回undefined,简单地说,你可以说yield关键字是断点,函数每次暂停,只有在使用迭代器调用它时才恢复,对于我们的例子:_getMeDrink.next()这是一个迭代器的例子,它帮助我们访问函数中的每个断点。
生成器示例: 异步/等待
如果你看到async/await的实现,你会看到生成器函数和承诺被用来使async/await工作,请指出任何建议,欢迎。
这真的很简单,它是这样工作的
Yield关键字只是帮助在任何时间异步暂停和恢复一个函数。 此外,它还有助于从生成器函数返回值。
以这个简单的生成器函数为例:
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.next()之前,它不会执行前两行代码,然后第一个yield将暂停函数。 要继续该函数直到下一个暂停点(yield关键字),需要调用_process.next()。
您可以将多个yield看作是javascript调试器中单个函数中的断点。直到 你告诉导航下一个断点,它不会执行代码 块。(注意:不阻塞整个应用程序)
但是当yield执行暂停和恢复行为时,它也可以返回一些结果{value: any, done: boolean} 根据前面的函数,我们没有输出任何值。如果我们查看之前的输出,它将显示相同的{value: undefined, done: false} 值未定义。
让我们深入研究yield关键字。可选地,您可以添加表达式和设置分配一个默认可选值。(官方文档语法)
[rv] = yield [expression];
表达式:从生成器函数返回的值
yield any;
yield {age: 12};
rv:返回传递给生成器next()方法的可选值
简单地,您可以使用这种机制将参数传递给process()函数,以执行不同的yield部分。
let val = yield 99;
_process.next(10);
now the val will be 10
现在就试试
用法
懒惰的评价 无限的序列 异步控制流
引用:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield http://javascript.tutorialhorizon.com/2015/09/16/generators-and-yield-in-es6/ https://strongloop.com/strongblog/how-to-generators-node-js-yield-use-cases/
迟回答,也许现在每个人都知道收益率,但一些更好的文件已经出现。
将James Long的《Javascript的未来:生成器》中的一个例子改编为官方的Harmony标准:
function * foo(x) {
while (true) {
x = x * 2;
yield x;
}
}
当你调用foo时,你会得到一个Generator对象,它有一个next 方法。”
var g = foo(2);
g.next(); // -> 4
g.next(); // -> 8
g.next(); // -> 16
收益率有点像回报,你会得到一些回报。Return x返回x的值,但yield x返回一个函数,它为您提供了一个迭代到下一个值的方法。如果您有一个潜在的内存密集型过程,您可能希望在迭代期间中断这个过程,那么这个方法很有用。
推荐文章
- 在数组中获取所有选中的复选框
- 如何为Firebase构建云函数,以便从多个文件部署多个函数?
- 如何发送推送通知到web浏览器?
- AngularJS:工厂和服务?
- js:将一个组件包装成另一个组件
- 父ng-repeat从子ng-repeat的访问索引
- JSHint和jQuery: '$'没有定义
- 模仿JavaScript中的集合?
- 用JavaScript验证电话号码
- 如何在HTML5中改变视频的播放速度?
- 谷歌地图API v3:我可以setZoom后fitBounds?
- ES6/2015中的null安全属性访问(和条件赋值)
- 与push()相反;
- JS字符串“+”vs concat方法
- AngularJS使用ng-class切换类