参考:js generator
我们先复习函数的概念。一个函数是一段完整的代码,调用一个函数就是传入参数,然后返回结果:
function foo(x) {
return x + x;
}
var r = foo(1); // 调用foo函数
函数在执行过程中,如果没有遇到return
语句(函数末尾如果没有return
,就是隐含的return undefined;
),控制权无法交回被调用的代码。
generator跟函数很像,定义如下:
function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}
generator和函数不同的是,generator由function*
定义(注意多出的*
号),并且,除了return
语句,还可以用yield
返回多次。
大多数同学立刻就晕了,generator就是能够返回多次的“函数”?返回多次有啥用?
还是举个栗子吧。
我们以一个著名的斐波那契数列为例,它由0
,1
开头:
0 1 1 2 3 5 8 13 21 34 ...
要编写一个产生斐波那契数列的函数,可以这么写:
function fib(max) {
var
t,
a = 0,
b = 1,
arr = [0, 1];
while (arr.length < max) {
[a, b] = [b, a + b];
arr.push(b);
}
return arr;
}
// 测试:
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
函数只能返回一次,所以必须返回一个Array
。但是,如果换成generator,就可以一次返回一个数,不断返回多次。用generator改写如下:
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
直接调用试试:
fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}
直接调用一个generator和调用函数不一样,fib(5)
仅仅是创建了一个generator对象,还没有去执行它。
调用generator对象有两个方法,一是不断地调用generator对象的next()
方法:
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}
next()
方法会执行generator的代码,然后,每次遇到yield x;
就返回一个对象{value: x, done: true/false}
,然后“暂停”。返回的value
就是yield
的返回值,done
表示这个generator是否已经执行结束了。如果done
为true
,则value
就是return
的返回值。
当执行到done
为true
时,这个generator对象就已经全部执行完毕,不要再继续调用next()
了。
第二个方法是直接用for ... of
循环迭代generator对象,这种方式不需要我们自己判断done
:
'use strict'
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
for (var x of fib(10)) {
console.log(x); // 依次输出0, 1, 1, 2, 3, ...
}
generator和普通函数相比,有什么用?
因为generator可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数,利用这一点,写一个generator就可以实现需要用面向对象才能实现的功能。例如,用一个对象来保存状态,得这么写:
var fib = {
a: 0,
b: 1,
n: 0,
max: 5,
next: function () {
var
r = this.a,
t = this.a + this.b;
this.a = this.b;
this.b = t;
if (this.n < this.max) {
this.n ++;
return r;
} else {
return undefined;
}
}
};
用对象的属性来保存状态,相当繁琐。
generator还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。这个好处要等到后面学了AJAX以后才能体会到。
没有generator之前的黑暗时代,用AJAX时需要这么写代码:
ajax('http://url-1', data1, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-2', data2, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-3', data3, function (err, result) {
if (err) {
return handle(err);
}
return success(result);
});
});
});
回调越多,代码越难看。
有了generator的美好时代,用AJAX时可以这么写:
try {
r1 = yield ajax('http://url-1', data1);
r2 = yield ajax('http://url-2', data2);
r3 = yield ajax('http://url-3', data3);
success(r3);
}
catch (err) {
handle(err);
}
看上去是同步的代码,实际执行是异步的。
相关推荐
### 知识点一:JavaScript 箭头函数 ES6(ECMAScript 2015)标准中引入了一种新的函数表达式——箭头函数(Arrow Function)。箭头函数提供了一种更简洁的函数写法,它主要有以下几个特点: 1. **简洁语法**:箭头...
这篇文档主要探讨了ES6(ECMAScript 2015)中引入的一些新特性,包括箭头函数、生成器(generator)、Date对象以及JSON。这些特性极大地丰富了JavaScript的功能,使得代码更加简洁和高效。 首先,箭头函数是ES6中的...
### JavaScript Generator函数深度解析与应用实践 #### 一、引言 在 ES6 之前,JavaScript 中的迭代器通常依赖于传统的循环结构(如 `for` 循环)结合数组或者对象来实现。这种方式虽然简单易懂,但在处理大规模...
总的来说,JS Generator函数通过引入`yield`关键字,为JavaScript异步编程提供了一种优雅且易于理解的解决方案。它减少了回调函数的使用,避免了回调地狱,并且在一定程度上解决了Promise链式调用的冗余。通过使用...
在Node.js中,Generator还可以用于实现轻量级的并发控制,通过控制Generator函数的执行来管理不同任务的执行顺序和状态。 为了使用Generator函数,需要在函数声明时使用星号(*)来标识这是一个Generator函数。在...
Generator函数是es6提供的一种异步编程的解决方案,语法行为与传统函数完全不一样。 Generator函数有多种理解角度,从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。 执 行Generator...
《JavaScriptES6函数式编程入门经典》... ●理解真实的函数式类库,并创建一个模拟underscore.js的函数式类库 ●实践纯错误处理技术,例如函子和Monad ●了解ES6的函数式编程特性,例如扩展运算符和Generator
thunk 函数(Generator 函数实现自动流程管理原理)说明Thunk 函数是用来解决 JS 中传名调用的一种实现方式Thunk 函数是一个单参数函数,
`getData`和`getTpl`函数分别用于执行不同的AJAX请求,它们接受一个URL和一个回调函数,当请求完成后,回调函数被调用并将结果传递给Generator函数的`next`方法。 `render`函数用于渲染模板,它接收数据和模板字符...
本项目“generator-ajax.zip”聚焦于JavaScript中的几个关键概念:Generator、js进程中断、异步操作的同步处理、以及如何重写alert和confirm来中断程序执行。通过结合html、Generator、thunk和ajax技术,我们可以...
JavaScript 的 Generator 是 ES6 引入的一种新的数据类型,它提供了一种创建迭代器(iterator)的机制,允许函数保存执行状态并能暂停和恢复执行。Generator 函数由 `function*` 关键字定义,其中的 `*` 表明这是一...
Generator函数是JavaScript中的一个特殊函数,其特征是在函数声明前加上`function*`关键字。Generator函数可以暂停和恢复执行,通过`yield`关键字来控制。在Express中结合Generator,我们可以利用`co`库(或Koa框架...
在JavaScript的世界里,Generator函数是一种特殊的函数,它允许我们创建迭代器,以便在执行流程中暂停和恢复。Generator函数的核心特点在于使用`*`符号来标识,并通过`yield`关键字来控制流。在这个名为"js代码-实现...
在JavaScript的世界里,Generator函数是一种特殊的函数,它允许我们创建可暂停执行的函数,从而实现对异步操作的控制,也可以被理解为一种轻量级的状态机。Generator函数的引入,极大地改善了JavaScript中处理复杂...
JavaScript中的箭头函数和普通函数在使用上有显著的差异,这些差异主要体现在以下几个方面: 1. **函数定义的简洁性**: - 箭头函数的语法更紧凑,可以视为匿名函数的一种简写形式。如果函数体只包含一个表达式,...
总的来说,迭代器和Generator函数是ES6中强大的工具,它们为JavaScript提供了更灵活的数据处理方式和异步控制流,大大提升了代码的可读性和可维护性。在实际开发中,特别是在处理复杂的数据结构和异步任务时,这些...