ES6 Generator函数(2)

1.Generator 与 协程

协程是一种程序运行的方式,可以理解为"写作的线程",或者"协作的函数",协程既可以单线程实现,也可以多线程实现;
前者是一种特殊的子例程,后者是一种特殊的线程。

2.Generator应用

Generator 可以暂停函数执行,返回任意表达式的值。这种特点使得Generator有多种应用场景。

3.Generator异步操作的同步化表达

Generator函数的暂停执行效果,意味着可以把异步操作写在yield语句里面。等到调用next方法的时候再往后执行。
这是继上等同于不需要再写回调函数了。
所以Generator函数的一个重要的实际意义就是处理异步操作,改写回调函数。

    {
        function* loadUI(){
            showLodingScreen();
            yield loadUIDataAsynchronously();
            hideLodingScreen();
        }

        let loader = loadUI();

        //加载UI
        loader.next();

        //卸载UI
        loader.next();
    }

    上述代码中,第一次调用loadUI函数时候,该函数不会执行,仅返回一个遍历器。下一步对该函数调用next方法,
    则会显示Loading页面(showLodingScreen()),并且异步加载数据(loadUIDataAsynchronously)。等到数据加载
    完成,再一次调用next方法,则会隐藏loading界面。可以看到,这种写法的好处就是所有Loading页面的逻辑,都被封装到
    一个函数中,按部就班非常清晰。
    

    Generator部署AJAX操作
    {
        function* main(){
            let result = yield request("http://some.url");
            let resp = JSON.parse(result);
            console.log(resp.revalue);
        }

        function request(url){
            makeAjaxCall(url, function(response){
                it.next(response);
            })
        }

        let it = main();
        it.next();
    }

    上面的main函数就是用过AJAX操作读取数据。可以看到,除了多一个yield基本与同步操作的写法一样。

4.控制流管理

如果一个多部操作非常耗时,采用回调函数可能会写成下面这样。



    {
        step1(function(value1){
            step2(function (value2){
                step3(function (value3){
                    step4(function (value4){
                        //do something.
                    })
                })
            })
        })
    }

    //采用promise
    {
        Promise.resolve(step1)
            .then(step2)
            .then(step3)
            .then(step4)
            .then(function(value4){
                // do something
            },function(err){
                console.log(err);
            })
    }

    //采用Generator函数
    {
        function* longRuningTask(value1) {
            try {
                let value1 = yield step1(value1);
                let value2 = yield step1(value2);
                let value3 = yield step1(value3);
                let value4 = yield step1(value4);
            } catch (e) {
                //some err msg;
            }
        }

        // 然后使用一个函数按次序自动执行所有步骤
        scheduler(longRuningTask(initialValue));
        function scheduler(task){
            let taskObj = task.next(task.value);
            //如果Generator函数未结束,就继续调用
            if(!taskObj.done){
                task.value = taskObj.value;
                scheduler(task);
            }
        }
    }
    这种方法只能用于所用同步操作,及所有的task都必须是同步的。

5.部署iterator接口

{
        function* iterator(obj) {
            let keys = Object.keys(obj);
            for(let i=0; i< keys.length; i++){
                let key = keys[i];
                yield [key,obj[key]];
            }
        }

        let myObj = {foo:3, bar:7};

        for(let [key,value] of iterator(myObj)){
            console.log(key,value);
        }
        //foo 3
        //bar 7
    }

    // 上述代码中,myObj是一个普通对象,通过iterator函数就有了Iterator接口。也就是说,可以再任意对象上部署next方法。
  • 参考文献<ES6标准入门> 阮一峰著
发布了85 篇原创文章 · 获赞 16 · 访问量 6108

猜你喜欢

转载自blog.csdn.net/qq_43955202/article/details/104347867