Javascript 异步编程魔法

JerryXia 发表于 , 阅读 (26)

在单线程执行的 Javascript 中,异步最著名的是 Ajax,但是你仅仅知道这些吗?

asynchronous-1

单线程执行

Two: 嘿,哥们儿,快点,我特么快憋不住了。

One: 我要三分钟,你先等着,完了叫你~

Two: 好的,记得叫我啊~ 你(Three)也等着吧,完了叫你~

Three: 等不了了,我回家换裤子吧!

所谓”单线程”,就是内存会为任务形成一个任务队列,让任务排队并挨个执行,例如,队列里有 One、Two、Three 3个任务,执行顺序为: One -> Two -> Three;这种执行的方式很清晰明了,特点是必须得 One 执行完才能执行 Two,很像我们生活中的银行排队办理业务,更像我们排队上老司机的车!!!

asynchronous-2

可是,这种方式的缺点也很明显,前面的任务没执行完,后面的任务都必须等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段 Javascript 代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。

上述执行方式中,程序的执行顺序与任务的排列顺序是一致且同步的。

如何异步

所谓的异步,就是每一个任务有一个或多个回调函数(callback),One 任务结束后,不是执行 Two 任务,而是执行回调函数,Two 任务不需要等 One 任务结束就执行,所以程序的执行顺序与任务的排列顺序是异步的。

asynchronous-3

“异步模式”非常重要,特别是在如今以性能和用户体验为主导的时代;耗时很长的操作都应该异步执行,避免用户等待时间过长,在这方面最好的方法就是采用 Ajax。在服务器端,”异步模式”甚至是唯一的模式,因为执行环境是单线程的,我们都知道,短时间内服务器被 http请求是有瓶颈的,一旦允许同步执行所有 http 请求,服务器性能会急剧下降,很快就会失去响应,进而翻车!!!

下面将科普四种 Javascript 异步编程的几种方法,如果你能上手它们,将帮助你在日常应用场景中写出结构更合理、性能更出色、维护更方便的 Javascript 代码。

  • 回调函数
  • 事件监听
  • 高阶函数
  • 发布/订阅
  • promise 对象
  • 类库的封装
  • ES6 的 Generator

回调函数

假设有两个顾客在银行柜台排队办业务,Collie() 和 Akita();但是 Collie() 没取多少钱却特别墨迹 ( 执行耗时较长 ),Akita() 有点等不了,心里有点想打人的冲动。

    Collie();    Akita();

asynchronous-4

此时,我们可以这么处理,把同步操作变成了异步操作,Collie() 不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。

    function Collie(callback){            setTimeout(function () {          // Collie要办理的业务(执行方法)          callback();        }, 2000);    }    Collie(Akita);

回调函数的优点是简单,轻量级;但是这么一写代码的话,容易形成各部分高耦合,而且每个任务只能回调一个函数,当此类任务过多时容易产生意大利面条式的代码,不利于程序的可读性和维护性。

事件监听

顾名思义,这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,JS 和 浏览器提供的原生方法基本都是基于事件触发机制的,耦合度很低,不过事件不能得到流程控制。

    Collie.on("evt", Akita);    function dogs(){    setTimeout(function(){        Collie.trigger("evt");        })    }

高阶函数(泛函数)

高阶听上去就像是一种先进的编程技术的一个深奥术语,一开始我看到的时候我也这样认为的,然而,然而细研究之后,发现高阶函数只是将函数作为参数或返回值的函数(后续我会专门写一篇深入浅出系列谈谈高阶函数)。

asynchronous-5

下面我请你尝尝我的手艺,你就知道这是一道什么菜了。

    var Collie = function(str1){        this.add = function (str2){    return str1 + ' ' + str2;    };        return add;        };        console.log(Collie('Hello')('World'));// Hello World
这种方法解耦程度很低,但是当参数过多时程序可读性非常不友好。

不信?下面我就用意大利面条式的代码吓唬吓唬你!!!

    step1(function(res1){    step2(function(res2){        step3(function(res3){             step4(function(res4){             step5(function(res5){            //...        });