• JavaScript中的异步编程


    异步编程,是JavaScript编程中重要的一部分,最近学习了阮一峰老师的《深入掌握 ECMAScript 6 异步编程》系列文章,特意输出一篇学习笔记。
    
    • 1

    传统的四种异步编程方法

    回调函数

    JavaScript 语言对异步编程的实现,就是回调函数。所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数。

    假设有三个函数f1f2f3f2需要等待f1的执行结果,这时最简单的方法就是把f2写成f1的回调函数:

    function f1(callback){
     setTimeout(()=>{
      console.log(1);
      callback();
     },1000);
    };
    
    function f2(){
     console.log(2);
    }
    
    function f3(){
     console.log(3);
    }
    
    f1(this.f2);
    f3();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    回调函数是异步编程最基本的方法,通过这种方法,函数f1不会阻塞程序的运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。

    事件监听

    JavaScript 事件处理是异步的。在 JavaScript 中,事件监听器会被添加到事件队列,等待主执行线程的处理。当主线程空闲时,事件队列中的事件会按顺序被执行。因此,事件回调函数不会阻塞主线程,也不会导致页面假死。

    事件驱动模式,这种方法的优点是比较容易理解,并且可以同时绑定多个事件,每个事件可以指定多个回调函数,有利于实现模块化。

    发布/订阅

    这种异步编程是通过发布/订阅模式来实现的,这种方法的性质与“事件监听”类似。

    这是一种广泛应用于异步编程的模式,是回调函数的事件化,常常用来解耦业务逻辑。事件的发布者无需关注订阅的侦听器如何实现业务逻辑,甚至不用关注有多少个侦听器存在。数据通过消息的方式可以灵活的传递。 ——《深入浅出Nodejs》

    Promises对象

    Promises是一个对象,它为异步编程提供了一个统一的接口,关于Promise的详细解释,我曾经做过一个很详细的用法说明

    使用Promises对象实现异步编程时,每一个异步任务返回一个Promise对象,该对象有一个then方法,开发者可以在then方法中指定回调函数。

    还是以函数f1f2f3为例子,这是后的代码就应该是下面这个样子:

    function f1(){
     var a = new Promise((res, rej) => {
      setTimeout(() => {
       console.log(1);
       res('1 done');
      }, 1000);
     });
     return a;
    };
    
    function f2(){
     console.log(2);
    }
    
    function f3(){
     console.log(3);
    }
    
    f1().then(() => {
     this.f2();
    })
    f3();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    和前面几种方法相比,Promise的回调函数变成了链式写法,而且Promises对象有一整套的配套方法,可以实现很多强大的功能。

    ECMAScript 6中的四种异步编程方法

    Generator函数

    Generator函数最大的特点就是可以暂停执行,它和普通函数的在写法上有两个区别:

    • 在函数名之前加星号以示区别
    • 异步操作需要暂停的地方,使用yield语句注明
    function* gen(x){
      var y = yield x + 2;
      return y;
    }
    var g = gen(1);
    g.next() // { value: 3, done: false }
    g.next() // { value: undefined, done: true }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用星号标记以后,整个Generator函数就是一个封装的异步任务,yield语句就是异步操作要暂停的地方。

    和普通函数不同的是,Generator函数执行之后返回的是一个指针对象,而不是return的值

    上面的代码中,var g = gen(1);调用Generator函数会返回一个内部指针g。指针g有一个next方法,会执行异步任务的第一阶段(既指针指向内部的第一个yield语句)。next方法会返回一个对象,表示当前阶段的信息(value属性和done属性),其中value属性指的是当前yield语句后面表达式的值,done属性是一个布尔值,表示当前Generator函数是否执行完毕。

    Generator函数的数据交换和错误处理

    用Generator函数来处理异步编程的原因,是因为它有暂停执行和恢复执行的能力,并且Generator函数有两个特性:函数体内外数据交换机制和错误处理机制。

    内外数据交换

    next方法的返回值是一个对象,对象中有一个value属性,这个value属性就是Generator函数向函数体外部输出的数据。

    同时,next方法也可以接受一个参数,这个参数就是向Generator函数体内输入的数据,

    function* gen(x){
      var y = yield x + 2;
      return y;
    }
    
    var g = gen(1);
    g.next() // { value: 3, done: false }
    g.next(2) // { value: 2, done: true }
    console.log(y) // 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    错误处理机制
    function* gen(x){
      try {
        var y = yield x + 2;
      } catch (e){ 
        console.log(e);
      }
      return y;
    }
    
    var g = gen(1);
    g.next();
    g.throw('出错了')// 出错了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    async函数

    async函数是一种Generator函数的语法糖。和前面的Generator函数相比,在写法上async函数就是将星号替换成了async,将yield替换成了await:

    async function gen(x){
      var y = await x + 2;
      return y;
    }
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    【大数据】es Elasticsearch 时间分组聚合查询
    1119 Pre- and Post-order Traversals
    深入解析Pancakeswap Prediction|博饼预测玩法
    麒麟信安操作系统衍生产品解决方案 | 安全探针软件,竖起内网安全护城墙
    Vue(三):样式绑定、条件渲染、列表渲染、列表过滤与列表排序
    数据库系统概论(超详解!!!)第三节 关系数据库标准语言SQL(Ⅴ)
    【文件操作的重难点详解】
    Python大作业——爬虫+可视化+数据分析+数据库(可视化篇)
    STM32的BOOT1和BOOT0查找及配置-都有BOOT1引脚的
    Java 新手如何使用Spring MVC 中的查询字符串和查询参数
  • 原文地址:https://blog.csdn.net/Dominic_W/article/details/133656060