zoukankan      html  css  js  c++  java
  • 读书笔记-你不知道的JS中-函数生成器

    这个坑比较深 可能写完我也看不懂(逃

      ES6提供了一个新的函数特性,名字叫Generator,一开始看到,第一反应是函数指针?然而并不是,只是一个新的语法。

    入门

      简单来说,用法如下:

        function* fn() {
            console.log(1);
            //暂停!
            yield;
            //调用next方法继续执行
            console.log(2);
        }
        var iter = fn();
        iter.next(); //1
        iter.next(); //2

      1、函数生成器特点是函数名前面有一个‘*’

      2、通过调用函数生成一个控制器

      3、调用next()方法开始执行函数

      4、遇到yield函数将暂停

      5、再次调用next()继续执行函数

    消息传递

      除了暂停和继续执行外,生成器同时支持传值。

      用法如下:

        function* fn() {
            var a = yield 'hello';
            yield;
            console.log(a);
        }
        var iter = fn();
        var res = iter.next();
        console.log(res.value); //hello
        iter.next(2);
        iter.next(); //2

      可以看到,yield后面有一个字符串,在第一次调用next时,暂停在这里且返回给了iter.next()。

      而暂停的地方是一个赋值语句,需要一个变量给a,于是next()方法中传了一个参数2替换了yield,最后打印a得到了2。

    异步应用   

      通过yield来实现异步控制流程:

        function fn(a, b) {
            //假设这是一个ajax请求
            ajax('url' + a + b, function(data) {
                //数据请求到会执行it.next
                it.next(data);
            });
        }
        //这里是函数生成器
        function* g() {
            //当异步操作完毕yield会得到值
            //这里会自动继续执行
            var text = yield fn(a, b);
            console.log(text);
        }
        var it = g();
        it.next();

      这里做了简化处理,忽略了一些错误处理。

      确实很巧妙,通过回调函数来继续执行函数生成器,然后得到数据。

      然而,直接在回调里拿数据不行么。书上讲,这样异步操作符合大脑思考模式,函数的执行看起来‘同步’了。

    yield+promise

      重点来了。

      先回忆之前promise对异步的实现: 

        function request(url) {
            return new Promise(function(resolve, reject) {
                //ajax异步请求完成会调用resolve决议
                ajax(url, resolve);
            });
        }
        request('url').then(function(res) {
            console.log(res);
        })

      流程大概是调用函数传入url,由于会立即决议,触发ajax请求函数。异步请求完调用调用回调函数,也就是resolve,然后根据返回的resolve调用then方法获取数据。

      现在将yield与promise综合在一起:

        function foo(x) {
            return request('url' + x);
        }
        //等待promise决议值返回
        function* fn() {
            var text = yield foo(1);
        }
        var it = fn();
        //返回一个promise
        var p = it.next().value;
        //对promise处理
        p.then(function(text) {
            //这里继续执行生成器
            it.next(text);
        })

    封装

      可以将上面的yield+promise进行封装,得到下面的函数:

        function run(gen) {
            //获取除了生成器本身以外的参数
            var args = [].slice.call(arguments, 1),
                it;
            //it = main()
            it = gen.apply(this, args);
            return Promise.resolve().then(function handleNext(value) {
                //第一次启动无value
                var next = it.next(value);
                return (function handleResult(next) {
                    //执行完毕返回
                    if (next.done) {
                        return next.value;
                    } else {
                        //如果还有就决议next.value传给handleNext
                        return Promise.resolve(next.value).then(handleNext, function(err) {});
                    }
                })(next);
            });
        }
        //这是一个函数生成器
        function* main() {
            //...
        };
        //该调用会自动异步运行直到结束
        run(main);

      如果有两个异步操作,获取到返回的两个数据后,再进行第三个异步操作,可以这么做:

        function foo() {
            var p1 = request('url1'),
                p2 = request('url2');
            //每一个request异步请求完成后会自动解除yield
            var r1 = yield p1,
                r2 = yield p2;
            var r3 = yield request('url3' + r1 + r2);
            console.log(r3);
        }

      

    坦白的讲,我不知道该写什么了,看懂后面的再来填坑。

  • 相关阅读:
    Java实现 LeetCode 69 x的平方根
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 66 加一
    Java实现 LeetCode 66 加一
    CxSkinButton按钮皮肤类
  • 原文地址:https://www.cnblogs.com/QH-Jimmy/p/6544767.html
Copyright © 2011-2022 走看看