`

js 函数 generator

    博客分类:
  • js
 
阅读更多

参考: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就是能够返回多次的“函数”?返回多次有啥用?

还是举个栗子吧。

我们以一个著名的斐波那契数列为例,它由01开头:

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是否已经执行结束了。如果donetrue,则value就是return的返回值。

当执行到donetrue时,这个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 箭头函数 generator Date JSON

    ### 知识点一:JavaScript 箭头函数 ES6(ECMAScript 2015)标准中引入了一种新的函数表达式——箭头函数(Arrow Function)。箭头函数提供了一种更简洁的函数写法,它主要有以下几个特点: 1. **简洁语法**:箭头...

    浅析JavaScript 箭头函数 generator Date JSON_.docx

    这篇文档主要探讨了ES6(ECMAScript 2015)中引入的一些新特性,包括箭头函数、生成器(generator)、Date对象以及JSON。这些特性极大地丰富了JavaScript的功能,使得代码更加简洁和高效。 首先,箭头函数是ES6中的...

    JavaScript Generator函数深度解析与应用实践

    ### JavaScript Generator函数深度解析与应用实践 #### 一、引言 在 ES6 之前,JavaScript 中的迭代器通常依赖于传统的循环结构(如 `for` 循环)结合数组或者对象来实现。这种方式虽然简单易懂,但在处理大规模...

    JS Generator 函数的含义与用法实例总结

    总的来说,JS Generator函数通过引入`yield`关键字,为JavaScript异步编程提供了一种优雅且易于理解的解决方案。它减少了回调函数的使用,避免了回调地狱,并且在一定程度上解决了Promise链式调用的冗余。通过使用...

    JavaScript 中使用 Generator的方法

    在Node.js中,Generator还可以用于实现轻量级的并发控制,通过控制Generator函数的执行来管理不同任务的执行顺序和状态。 为了使用Generator函数,需要在函数声明时使用星号(*)来标识这是一个Generator函数。在...

    js中Generator函数的深入讲解

    Generator函数是es6提供的一种异步编程的解决方案,语法行为与传统函数完全不一样。 Generator函数有多种理解角度,从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。 执 行Generator...

    JavaScript ES6函数式编程入门经典

    《JavaScriptES6函数式编程入门经典》... ●理解真实的函数式类库,并创建一个模拟underscore.js的函数式类库  ●实践纯错误处理技术,例如函子和Monad  ●了解ES6的函数式编程特性,例如扩展运算符和Generator

    xingpengchao#leetcode#thunk函数(Generator函数实现自动流程管理原理)1

    thunk 函数(Generator 函数实现自动流程管理原理)说明Thunk 函数是用来解决 JS 中传名调用的一种实现方式Thunk 函数是一个单参数函数,

    js使用generator函数同步执行ajax任务

    `getData`和`getTpl`函数分别用于执行不同的AJAX请求,它们接受一个URL和一个回调函数,当请求完成后,回调函数被调用并将结果传递给Generator函数的`next`方法。 `render`函数用于渲染模板,它接收数据和模板字符...

    generator-ajax.zip

    本项目“generator-ajax.zip”聚焦于JavaScript中的几个关键概念:Generator、js进程中断、异步操作的同步处理、以及如何重写alert和confirm来中断程序执行。通过结合html、Generator、thunk和ajax技术,我们可以...

    深入理解js generator数据类型.docx

    JavaScript 的 Generator 是 ES6 引入的一种新的数据类型,它提供了一种创建迭代器(iterator)的机制,允许函数保存执行状态并能暂停和恢复执行。Generator 函数由 `function*` 关键字定义,其中的 `*` 表明这是一...

    Node.js-在Express中愉快地使用Generator

    Generator函数是JavaScript中的一个特殊函数,其特征是在函数声明前加上`function*`关键字。Generator函数可以暂停和恢复执行,通过`yield`关键字来控制。在Express中结合Generator,我们可以利用`co`库(或Koa框架...

    js代码-实现Generator函数的run

    在JavaScript的世界里,Generator函数是一种特殊的函数,它允许我们创建迭代器,以便在执行流程中暂停和恢复。Generator函数的核心特点在于使用`*`符号来标识,并通过`yield`关键字来控制流。在这个名为"js代码-实现...

    js代码-Generator函数:状态机-生成器

    在JavaScript的世界里,Generator函数是一种特殊的函数,它允许我们创建可暂停执行的函数,从而实现对异步操作的控制,也可以被理解为一种轻量级的状态机。Generator函数的引入,极大地改善了JavaScript中处理复杂...

    【JavaScript源代码】JavaScript中箭头函数与普通函数的区别详解.docx

    JavaScript中的箭头函数和普通函数在使用上有显著的差异,这些差异主要体现在以下几个方面: 1. **函数定义的简洁性**: - 箭头函数的语法更紧凑,可以视为匿名函数的一种简写形式。如果函数体只包含一个表达式,...

    ES6中的迭代器、Generator函数及Generator函数的异步操作方法

    总的来说,迭代器和Generator函数是ES6中强大的工具,它们为JavaScript提供了更灵活的数据处理方式和异步控制流,大大提升了代码的可读性和可维护性。在实际开发中,特别是在处理复杂的数据结构和异步任务时,这些...

Global site tag (gtag.js) - Google Analytics