• javascript 异步编程


       js 是一种"单线程”(single thread)执行环境的语言,所以在任务执行的过程中是按照队列的形式,当一个任务执行完再执行下一个任务,这样的模式会因为一个任务执行时间较长的时候出现性能问题,例如页面假死状态。
    为了解决这个问题,js将执行模式分为两种:同步(synchronous)和异步(asynchronous)
       同步执行:后一个任务等待前一个任务执行完毕再执行。
       异步执行:前一个任务可传入一个回调函数,在执行完毕后调用回调函数,后一个任务不等前一个任务执行完毕就会执行。
       目前我总结的异步编程有一下几种方式:
    • 回调函数
    • 事件监听
    • 发布/订阅
    • promise
    • async/awaits
    1.回调函数
    对调函数是最简单直接的方法,给执行的异步函数传入一个函数作为回调函数,当异步返回结果的时候执行回调函数
    function cbFun() {
    console.log("hello word!");
    }
    function asyncFun(callback) {
    setTimeout(() => {
    callback();
    }, 3000);
    }
     
    asyncFun(cbFun);
     
    2.事件监听
    另一种思路采用事件驱动模式,任务的执行不取决于代码的顺序,而取决于事件的是否发生,这里用eventEmitter3 这个插件来实现
    function cbFun() {
    console.log("hello word!");
    }
    function asyncFun() {
    setTimeout(() => {
    emitter.emit("msg");
    }, 3000);
    }
    var emitter = new EventEmitter3();
    emitter.on("msg", cbFun);
    // 执行异步函数
    asyncFun()
    

      

    这种方法有点比较容易理解,可以绑定多个事件,每个事件都可以指定多个回调函数,可以”去耦合”(decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动,运行流程会变的不清晰。
     
    3.发布/订阅
    我们可以把事件驱动看作成信号驱动,我们假定存在一个”信号中心“,某个任务完成就会去信号中心发布一个信号,其他任务可以在信号中心订阅这个信号,从而指导自己什么时候开始执行,这种模式叫做”发布/订阅模式“(publish-subscribe pattern).下面是一种实现发布订阅模式的对象
    var PubSub = function() {
    this.list = {};
    };
    //给订阅者提供订阅的方法
    PubSub.prototype.subscribe = function(key, callback) {
    if (!this.list[key]) {
    this.list[key] = [];
    }
    this.list[key].push(callback);
    };
    //发布消息的功能
    PubSub.prototype.publish = function(key, args) {
    var fns = this.list[key];
    // 如果没有订阅过该消息的话,则返回
    if (!fns || fns.length === 0) {
    return;
    }
    var len = fns.length;
    while (len--) {
    fns[len].apply(this, args);
    }
    };
    // 取消订阅
    PubSub.prototype.unsubscribe = function(key, fn) {
    var fns = this.list[key];
    if (!fns || fns.length === 0) {
    return false;
    }
    if (!fn) {
    fns && (fns.length = 0);
    } else {
    // 将fn删除
    var len = fns.length;
    while (len--) {
    if (fns[len] === fn) {
    fns.splice(len, 1);
    }
    }
    }
    };
     
    下面利用发布/订阅模式实现异步编程
    var pubsub = new PubSub();
    pubsub.subscribe("msg", cbFun);
    function cbFun() {
    console.log("hello word!");
    }
    function asyncFun() {
    setTimeout(() => {
    pubsub.publish("msg");
    }, 3000);
    }
    asyncFun(); 
    这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
     
    4.Promise
    Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
    Promise对象有以下两个特点。
    (1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
    (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
    function cbFun() {
    console.log("hello word!");
    }
    function asyncFun(callback) {
    return new Promise((resolve, reject) => {
    setTimeout(() => {
    resolve();
    }, 3000);
    });
    }
    asyncFun().then(()=>{
    cbFun()
    }) 
    Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
     
    5.async/await
    目前async/await方法被作为前端异步的终极方案,因为其在语义化方面非常友好,对于代码的维护非常简单,只需要返回promise并await 它就好。
    function cbFun() {
    console.log("hello word!");
    }
    function asyncFun() {
    return new Promise((resolve, reject) => {
    setTimeout(() => {
    resolve();
    }, 3000);
    });
    }
    async function asyncFunArr() {
    await asyncFun();
    cbFun();
    }
    asyncFunArr();
    

      参考:

    Javascript异步编程的4种方法

     
     
     
     
  • 相关阅读:
    vue 快速开发
    java 查es
    es filter 的使用
    es查询例子
    es的基本查询
    linux top命令VIRT,RES,SHR,DATA的含义
    Redis和MC的对比
    决TIME_WAIT过多造成的问题
    MariaDB yum 安装
    more 命令相关
  • 原文地址:https://www.cnblogs.com/chrissong/p/10253193.html
Copyright © 2020-2023  润新知