17.1、Generator函数的异步应用


        /*
            异步编程对 Javascript 语言来说非常重要。
            Javascript 语言的执行环境是 “单线程” 的,如果没有异步编程,根本无法使用,不然会造成卡死。

            本章主要介绍 Generator 函数如何完成异步操作
        */

        /*
            17.1 传统方法
            
            es6 诞生以前,异步编程的方法大概有下面 4 种

                + 回调函数
                + 事件监听
                + 发布/订阅
                + Promise 对象

                Generator 函数将 Javascript 异步编程带入了一个全新的阶段
        */ 

        /*
            17.2 基本概念

            17.2.1 异步

                所谓 “异步”,简单来说就是一个任务不是连续完成的,可以理解成该任务被人分成两段,
                先执行第一段,然后转而执行其他任务,等做好准备后再回过头执行第二段。

                比如,有一个任务是读取文件进行处理,任务的第一段是向操作系统发出请求,要求读取文件。
                然后,程序执行其他任务,等到操作系统返回文件后再接着执行任务的第二段(处理文件)。
                这种不连续的执行就叫作异步。

                相应地,连续执行叫作同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能等待。


            17.2.2 回调函数

                Javascript 语言对异步编程的实现就是回调函数。
                所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务时便直接调用这个函数。
                回调函数的英文名字 callback,直译过来就是 “重新调用”
        */

        // 读取文件进行处理的代码如下

        fs.readFile('/etc/passwd', 'utf-8', function(err, data) {
            if(err) throw err
            console.log(data)
        })

        // 上面的代码中,readFile 函数的第三个参数就是回调函数,也就是任务的第二段。等到操作系统返回 /etc/passwd 文件以后,回调函数才会执行


        /*
            Promise 

            回调函数本身并没有问题,它的问题出现在多个回调函数嵌套上。假定读取 A 文件之后再读取 B 文件,代码如下:
        */

        fs.readFile(FileReaderA, 'utf-8', function(err, data) {
            fs.readFile(fileB, 'utf-8', function(err, data) {
                // ...
            })
        }) 

        /*
            不难想象,如果依次读取以上两个文件,就会出现多重嵌套。
            代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。
            因为多个异步操作形成了强耦合,只要有一个操作需要修改,它的上层回调函数和下层回调函数就都要跟着修改。
            这种情况就称为 “回调函数地狱 (callback hell)”

            Promise 对象就是为了解决这个问题而被提出来的。
            它不是新的语法功能,而是一种新的写法,允许将回调函数的嵌套改写成链式调用。采用 Promise 连续读取多个文件的写法如下:
        */

        var readFile = require('fs-readfile-promise')

        readFile(fileA) 
        .then(function (data) {
            console.log(data.toString())
        })
        .then(function () {
            return readFile(fileB)
        })
        .then(function (data) {
            console.log(data.toString())
        })
        .catch(function (err) {
            console.log(err)
        })

        /*
            上面的代码中,笔者使用了 fs-readfile-promise 模块,它的作用就是返回一个 Promise 版本的 readFile 函数。
            Promise 提供 then 方法加载回调函数,catch 方法捕捉执行过程中抛出的错误。

            可以看到,Promise 的写法只是回调函数的改进,使用 then 方法以后,异步任务的两段执行更清楚了,除此之外,并无新意。 

            Promise 的最大问题是代码冗余,原来的任务被 Promise 包装之后,无论什么操作,一眼看去都是许多 then 的堆积,原来的语义变得很不清楚            
        */






        /*
            17.3  Generator 函数

            17.3.1 协程

            传统的编程语言中早有异步编程的解决方案(其实是多任务的解决方案),其中一种叫作 “协程”,意思是多个线程互相协作,完成异步任务

            协程有点像函数,又有点像线程。它的运行流程大致如下:

                + 第一步:协程 A 开始执行
                + 第二步:协程 A 执行到一半,进入暂停状态,执行权转移到协程 B 中
                + 第三步:(一段时间后)协程 B 交还执行权
                + 第四步:协程 A 恢复执行

                上面流程的协程 A 就是异步任务,因为它分为两段(或多段)执行


                举例来说,读取文件的协程写法如下:
        */

        function *asyncJob() {
            // ...其他代码
            var f = yield readFile(fileA)
            // ...其他代码
        }

        /*
            上面的代码的函数 asyncJob 是一个协程,它的奥妙在于其中的 yield 命令。
            它表示执行到此处时,执行权将交给其他协程。也就是说,yield 命令是异步两个阶段的分界线。

            协程遇到 yield 命令就暂停,等到执行权返回,再从暂停的地方继续往后执行。
            它的最大优点是,代码的写法非常像同步操作,如果去除 yield 命令,几乎一摸一样。
        */ 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值