什么';JavaScript中的yield关键字是什么?
我听说JavaScript中有一个“yield”关键字,但我发现关于它的文档非常糟糕。有人能给我解释一下(或者推荐一个网站来解释)它的用法和它的用途吗?它用于迭代器生成器。基本上,它允许您使用过程代码生成(可能是无限的)序列。看。在我看来,天气相当不错 包含yield关键字的函数是一个生成器。当您调用它时,它的形式参数被绑定到实际参数,但它的主体并没有被实际计算。而是返回一个生成器迭代器。对生成器迭代器的next()方法的每次调用都会执行迭代算法的另一次传递。每个步骤的值都是由yield关键字指定的值。将yield视为return的生成器迭代器版本,指示算法每次迭代之间的边界。每次调用next(),生成器代码都会从yield后面的语句恢复什么';JavaScript中的yield关键字是什么?,javascript,yield,keyword,Javascript,Yield,Keyword,我听说JavaScript中有一个“yield”关键字,但我发现关于它的文档非常糟糕。有人能给我解释一下(或者推荐一个网站来解释)它的用法和它的用途吗?它用于迭代器生成器。基本上,它允许您使用过程代码生成(可能是无限的)序列。看。在我看来,天气相当不错 包含yield关键字的函数是一个生成器。当您调用它时,它的形式参数被绑定到实际参数,但它的主体并没有被实际计算。而是返回一个生成器迭代器。对生成器迭代器的next()方法的每次调用都会执行迭代算法的另一次传递。每个步骤的值都是由yield关键字指
回答晚了,可能现在每个人都知道
yield
,但是一些更好的文档已经出现了
将James Long的例子改编为官方和谐标准:
function * foo(x) {
while (true) {
x = x * 2;
yield x;
}
}
“当您调用foo时,将返回一个生成器对象,该对象具有下一个
方法。”
所以,
yield
有点像return
:你得到了回报return x
返回x
的值,但是yield x
返回一个函数,该函数为您提供了一个方法,可以迭代到下一个值。如果您有一个在迭代过程中可能需要中断的问题,则此选项非常有用。要给出完整的答案:yield
的工作原理与return
类似,但在生成器中
对于通常给出的示例,其工作原理如下:
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
当值2
被分配给y
,并在第一次产量停止后(返回0
)将其发送给生成器时,这一点起作用
这使我们能够了解一些非常时髦的东西。(查找协同程序)
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());
function* main() {
var result = yield loadFromDB('query')
}
简化/详细说明Nick Sotiros的答案(我认为这非常棒),我认为最好描述一下如何开始使用
yield
进行编码
在我看来,使用yield
的最大优点是它将消除我们在代码中看到的所有嵌套回调问题。很难看出一开始是怎么回事,这就是为什么我决定写这个答案(为了我自己,希望也是为了其他人!)
它的工作方式是引入一个共同例程的概念,这是一个可以自动停止/暂停的函数,直到它得到它所需要的。在javascript中,这由函数*
表示。只有function*
函数才能使用yield
下面是一些典型的javascript:
loadFromDB('query', function (err, result) {
// Do something with the result or handle the error
})
这是笨拙的,因为现在所有的代码(显然需要等待这个loadFromDB
调用)都需要在这个丑陋的回调中。这不好有几个原因
- 您的所有代码都缩进一级
- 你有这样一个目的})你需要在任何地方跟踪它
- 所有这些额外的
术语函数(err,result)
- 不太清楚您这样做是为了给
result
yield
,所有这些都可以在nice协同例程框架的帮助下在一行中完成
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());
function* main() {
var result = yield loadFromDB('query')
}
现在,当需要等待变量和内容加载时,主函数将在必要的地方产生。但是现在,为了运行它,您需要调用一个普通的(非协程函数)。一个简单的协同例程框架可以解决此问题,因此您只需运行以下操作:
start(main())
定义了启动(来自Nick Sotiro的回答)
现在,您可以拥有更具可读性、易于删除且无需修改缩进、函数等的漂亮代码
一个有趣的观察结果是,在本例中,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
- 此外,它有助于从生成器函数返回值李>
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');
}
让_进程=进程()
在调用\u进程之前。next()它不会执行前两行代码,然后第一个yield将暂停该函数。
要继续函数直到下一个暂停点(产生关键字),您需要调用\u process.next()
您可以认为,多个产量是单个函数中javascript调试器中的断点。直到
您告诉导航下一个断点,它不会执行代码
块(注意:不阻止整个应用程序)
但是,当yield执行这种暂停和恢复行为时,它也可以返回一些结果{value:any,done:boolean}
根据前面的函数,我们没有发出任何值。如果我们浏览前面的输出,它将显示相同的{value:undefined,done:false}
值未定义
让我们埋头干吧
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');
}
[rv] = yield [expression];
yield any;
yield {age: 12};
let val = yield 99;
_process.next(10);
now the val will be 10
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
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}
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+++++++++++");
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+++++++++++");
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);
}
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