我听说过JavaScript中的“yield”关键字,但我发现关于它的文档非常糟糕。有人能给我解释一下(或者推荐一个解释它的网站)它的用法和用途吗?
当前回答
不要忘记使用非常有用的“x of generator”语法来遍历生成器。根本不需要使用next()函数。
function* square(x){
for(i=0;i<100;i++){
x = x * 2;
yield x;
}
}
var gen = square(2);
for(x of gen){
console.log(x);
}
其他回答
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());
我还试图理解yield关键字。根据我目前的理解,在生成器中,yield关键字就像CPU上下文开关一样。当yield语句运行时,将保存所有状态(例如局部变量)。
除此之外,一个直接的结果对象将返回给调用者,如{value: 0, done: false}。调用者可以使用这个结果对象通过调用next()来决定是否再次“唤醒”生成器(调用next()是为了迭代执行)。
另一个重要的事情是,它可以将一个值设置为一个局部变量。这个值可以在“唤醒”生成器时由“next()”调用者传递。例如,it.next('valueToPass'),就像这样:"resultValue = yield slowQuery(1);"就像唤醒下一次执行时一样,调用者可以向执行注入一些运行结果(注入到局部变量)。因此,对于这个执行,有两种状态:
上次执行时保存的上下文。 这个执行的触发器注入的值。
因此,有了这个特性,生成器可以对多个异步操作进行排序。第一个异步查询的结果将通过设置局部变量(上面例子中的resultValue)传递给第二个异步查询。第二个异步查询只能由第一个异步查询的响应触发。然后第二个异步查询可以检查局部变量值以决定下一步,因为局部变量是第一个查询响应的注入值。
异步查询的困难在于:
回调地狱 除非在回调中将它们作为参数传递,否则将丢失上下文。
产量和发电机可以帮助这两个。
在没有yield和generator的情况下,对多个异步查询进行排序需要以参数为上下文的嵌套回调,不便于读取和维护。
下面是一个使用nodejs运行的链式异步查询示例:
const axios = require('axios');
function slowQuery(url) {
axios.get(url)
.then(function (response) {
it.next(1);
})
.catch(function (error) {
it.next(0);
})
}
function* myGen(i=0) {
let queryResult = 0;
console.log("query1", queryResult);
queryResult = yield slowQuery('https://google.com');
if(queryResult == 1) {
console.log("query2", queryResult);
//change it to the correct url and run again.
queryResult = yield slowQuery('https://1111111111google.com');
}
if(queryResult == 1) {
console.log("query3", queryResult);
queryResult = yield slowQuery('https://google.com');
} else {
console.log("query4", queryResult);
queryResult = yield slowQuery('https://google.com');
}
}
console.log("+++++++++++start+++++++++++");
let it = myGen();
let result = it.next();
console.log("+++++++++++end+++++++++++");
运行结果如下:
+++++++++++ 《削减战略武器条约》 +++++++++++
query1 0
+++++++++++ 新力 +++++++++++
query2 1
query4 0
下面的状态模式可以做类似的事情,上面的例子:
const axios = require('axios');
function slowQuery(url) {
axios.get(url)
.then(function (response) {
sm.next(1);
})
.catch(function (error) {
sm.next(0);
})
}
class StateMachine {
constructor () {
this.handler = handlerA;
this.next = (result = 1) => this.handler(this, result);
}
}
const handlerA = (sm, result) => {
const queryResult = result; //similar with generator injection
console.log("query1", queryResult);
slowQuery('https://google.com');
sm.handler = handlerB; //similar with yield;
};
const handlerB = (sm, result) => {
const queryResult = result; //similar with generator injection
if(queryResult == 1) {
console.log("query2", queryResult);
slowQuery('https://1111111111google.com');
}
sm.handler = handlerC; //similar with yield;
};
const handlerC = (sm, result) => {
const queryResult = result; //similar with generator injection;
if (result == 1 ) {
console.log("query3", queryResult);
slowQuery('https://google.com');
} else {
console.log("query4", queryResult);
slowQuery('https://google.com');
}
sm.handler = handlerEnd; //similar with yield;
};
const handlerEnd = (sm, result) => {};
console.log("+++++++++++start+++++++++++");
const sm = new StateMachine();
sm.next();
console.log("+++++++++++end+++++++++++");
运行结果如下:
+++++++++++ 《削减战略武器条约》 +++++++++++
query1 0
+++++++++++ 新力 +++++++++++
query2 1
query4 0
这真的很简单,它是这样工作的
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/
它用于迭代器生成器。基本上,它允许您使用过程代码制作(可能是无限的)序列。请参阅Mozilla的文档。
在我看来,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.
推荐文章
- 什么时候JavaScript是同步的?
- 如何在Typescript中解析JSON字符串
- Javascript reduce()在对象
- 在angularJS中& vs @和=的区别是什么
- 错误"Uncaught SyntaxError:意外的标记与JSON.parse"
- JavaScript中的querySelector和querySelectorAll vs getElementsByClassName和getElementById
- 给一个数字加上st, nd, rd和th(序数)后缀
- 如何以编程方式触发引导模式?
- setTimeout带引号和不带括号的区别
- 在JS的Chrome CPU配置文件中,'self'和'total'之间的差异
- 用javascript检查输入字符串中是否包含数字
- 如何使用JavaScript分割逗号分隔字符串?
- 在Javascript中~~(“双波浪号”)做什么?
- 谷歌chrome扩展::console.log()从后台页面?
- 未捕获的SyntaxError: