我听说过JavaScript中的“yield”关键字,但我发现关于它的文档非常糟糕。有人能给我解释一下(或者推荐一个解释它的网站)它的用法和用途吗?
当前回答
我还试图理解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* fibonacci() {
var a = -1, b = 1, c;
while(1) {
c = a + b;
a = b;
b = c;
yield c;
}
}
var fibonacciGenerator = fibonacci();
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}
迟回答,也许现在每个人都知道收益率,但一些更好的文件已经出现。
将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返回一个函数,它为您提供了一个迭代到下一个值的方法。如果您有一个潜在的内存密集型过程,您可能希望在迭代期间中断这个过程,那么这个方法很有用。
在我看来,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之前,您需要了解生成器。生成器是使用函数*语法创建的。Generator函数不执行代码,而是返回一种称为Generator的迭代器。当使用下一个方法给出一个值时,生成器函数将继续执行,直到遇到yield关键字。使用yield返回一个包含两个值的对象,一个是value,另一个是done(布尔值)。该值可以是数组、对象等。
推荐文章
- 在数组中获取所有选中的复选框
- 如何为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切换类