美文网首页
JS的异步方法

JS的异步方法

作者: 壹豪 | 来源:发表于2020-09-12 01:00 被阅读0次

    本文是我写的一个目录,具体内容会跳转我的其他文章,阅读性可能较差,抱歉

    众所周知,JS是单线程运行的,同一时刻只能执行一个任务,如果碰到一个执行时间很长的任务,那么后面所有的任务都需要排队,这样效率过于低下,因此诞生了异步,虽然还是只能执行一个任务,但是可以把耗时长优先级低的任务往后排。
    我们按出现的时间顺序来介绍不同的异步方法,便于记忆。

    1.回调函数(ES5)

    直接上代码:

    function foo1(callback){
        setTimeout(function(){
            callback();
        }, 1000)
    }
    function foo2(){
        let i = 10000;
        while(i){
            console.log(i--);
        }
    }
    
    foo1(foo2);
    console.log('urgent task')
    

    函数 foo2() 需要很久执行完毕,但是在后面有一个紧急任务console.log('urgent task')需要赶紧执行,那么就使用 foo1() 设置一个定时器 setTimeout() 来回调 foo2() 。原理是利用JS的 event loop 运行机制,利用定时器 setTimeout() 把 foo2() 插入宏任务队列,等下次执行宏任务时才运行。

    优点:简单,易部署
    缺点:不易于维护和阅读,高度耦合

    2.事件监听

    这种方式下,异步任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

    下面是两个函数 f1 和 f2,编程的意图是 f2 必须等到 f1 执行完成,才能执行。首先,为 f1 绑定一个事件(这里采用的 jQuery 的写法)

    f1.on('done', f2);
    

    上面这行代码的意思是,当 f1 发生 done 事件,就执行 f2。然后,对f1进行改写:

    function f1() {
      setTimeout(function () {
        // ...
        f1.trigger('done');
      }, 1000);
    

    上面代码中,f1.trigger(‘done’)表示,执行完成后,立即触发 done 事件,从而开始执行f2。

    这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合",有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。阅读代码的时候,很难看出主流程。

    3.发布订阅

    我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。

    首先,f2 向信号中心 jQuery 订阅 done 信号。

    jQuery.subscribe('done', f2);
    

    然后,f1进行如下改写:

    function f1() {
      setTimeout(function () {
        // ...
        jQuery.publish('done');
      }, 1000);
    }
    

    上面代码中,jQuery.publish(‘done’)的意思是,f1执行完成后,向信号中心 jQuery 发布 done 信号,从而引发f2的执行。
    f2 完成执行后,可以取消订阅(unsubscribe)

    jQuery.unsubscribe('done', f2);
    

    这种方法的性质与“事件监听”类似,但是明显优于后者。因为可以通过查看“消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。

    4.Promise

    见我的文章Promise总结

    5.Generator / yield

    Generator 是ES6里新出的一个语法
    在 function 后加上一个 * 即代表是一个 Generator 构造器,然后在 Generator 构造器中使用 yield 语法配合使用。每次使用 Generator 构造器的 next() 方法就会执行 Generator 的代码,然后每次遇到 yield x 就返回一个对象 {value: x, done: true/false},然后“暂停”。返回的 value 就是 yield 后面表达式的返回值,done 表示这个 Generator 是否已经执行结束了。如果 done 为 true,则 value 就是 return 的返回值。

    调用 Generator 对象有两个方法:

    1. 不断地调用 Generator 对象的 next() 方法
    function* fib(max) {
        var
            t,
            a = 0,
            b = 1,
            n = 0;
        while (n < max) {
            yield a;
            [a, b] = [b, a + b];
            n ++;
        }
        return;
    }
    
    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}
    
    1. 直接用 for ... of 循环迭代 Generator 对象
    '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, ...
    }
    
    6.async / await

    见我的文章超详细的 async / await

    [1].JS 异步编程六种方案
    [2].generator - 廖雪峰的官方网站

    相关文章

      网友评论

          本文标题:JS的异步方法

          本文链接:https://www.haomeiwen.com/subject/mhoyektx.html