宝哥软件园

用JavaScript实现异步编程模式的四种方法

编辑:宝哥软件园 来源:互联网 时间:2021-09-10

大家可能知道,Javascript语言的执行环境是“单线程”。

所谓“单线程”,就是一次只能完成一个任务。如果有多个任务,必须排队,前一个任务完成,然后执行下一个任务,依此类推。

这种模型的优点是实现相对简单,执行环境相对简单;缺点是只要一个任务需要很长时间,后面的任务就必须排队等待,会耽误整个程序的执行。常见的浏览器无响应(feign死亡),往往是因为某个Javascript代码长时间运行(比如无限循环),导致整个页面卡在这个地方,其他任务无法执行。

为了解决这个问题,Javascript语言将任务的执行模式分为两种:同步和异步。

“同步模式”是上一段的模式。后一个任务等待前一个任务的结束,然后执行它。程序的执行顺序与任务的排列顺序一致、同步;“异步模式”完全不同。每个任务都有一个或多个回调函数。前一个任务完成后,执行回调函数代替后一个任务,后一个任务在前一个任务完成前执行。因此,程序的执行顺序与任务的顺序不一致,这是异步的。

异步模式非常重要。在浏览器端,长时间的操作应该异步执行,以避免浏览器失去响应。最好的例子就是Ajax操作。在服务器端,“异步模式”甚至是唯一的模式,因为执行环境是单线程的。如果允许所有http请求同步执行,服务器的性能会急剧下降,很快就会失去响应。

本文总结了“异步模式”编程的四种方法。了解它们可以帮助你写出结构更合理、性能更好、维护更方便的Javascript程序。

一、回调函数

这是异步编程最基本的方法。

假设有两个函数f1和f2,后者等待前者的执行结果。

复制代码如下: f1();F2();

如果f1是一个耗时的任务,可以考虑重写f1并编写f2作为f1的回调函数。复制代码如下:function f1(回调){ 0

setTimeout(函数(){ 0

//f1的任务代码

回调();

}, 1000);

}执行代码变成如下:复制代码如下: f1(F2);

这样我们就把同步操作变成了异步操作,f1不会阻塞程序的运行,相当于先执行程序的主逻辑,耽误了耗时的操作。

回调函数的优点是简单,易于理解和部署,缺点是不利于代码的读取和维护,各个部分耦合性很强,过程会比较混乱,每个任务只能指定一个回调函数。

二、事件监控

另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而是取决于事件是否发生。

或者以f1和f2为例。首先,为f1绑定一个事件(这里使用jQuery)。复制代码如下:f1.on('done ',F2);上面的代码行意味着当f1完成事件时,f2将被执行。然后,重写f1:复制代码如下: function f1(){ 0

setTimeout(函数(){ 0

//f1的任务代码

f1 . trigger(' done ');

}, 1000);

}f1.trigger('done ')表示执行完成后,立即触发done事件,从而开始执行f2。

这种方法的优点是容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,并且可以解耦,有利于实现模块化。缺点是整个程序会变成事件驱动,运行过程会变得非常不清晰。

第三,发布/订阅

上一节中的“事件”可以理解为“信号”。

我们假设有一个“信号中心”。当一个任务执行时,它会向信号中心“发布”一个信号,其他任务可以向信号中心“订阅”这个信号,从而知道自己什么时候可以开始执行。这被称为“发布-订阅模式”,也称为“观察者模式”。

这个模式有很多实现,下面这个是Ben Alman的Tiny Pub/Sub,是jQuery的一个插件。

首先,f2订阅来自“信号中心”jQuery的“完成”信号。复制代码如下:jquery。订阅(“完成”,F2);然后,f1重写如下:复制代码如下: function f1(){ 0

setTimeout(函数(){ 0

//f1的任务代码

jquery . publish(' done ');

}, 1000);

}jQuery.publish('done ')表示f1执行完成后,会向jQuery发出“done”信号,触发f2执行。

此外,在f2完成执行后,也可以取消订阅。复制代码如下:jQuery。取消订阅(“完成”,F2);这种方法本质上类似于“事件监控”,但明显优于后者。因为我们可以通过查看消息中心,了解每个信号有多少信号,有多少用户,从而监控程序的运行。

四.承诺对象

Promises对象是CommonJS工作组提出的规范,旨在为异步编程提供统一的接口。

简单地说,想法是每个异步任务返回一个Promise对象,该对象有一个允许您指定回调函数的then方法。例如,f1的回调函数f2可以写成:复制代码如下:f1()。然后(F2);F1需要重写如下(这里使用jQuery的实现):复制代码的代码如下: function f1(){ 0

var dfd=$。递延();

setTimeout(函数(){ 0

//f1的任务代码

DFD . resolve();

}, 500);

返回dfd.promise

}这种方式编写的好处是回调函数采用链式的方式编写,可以清晰的看到程序流程,并且有一套完整的支持方法,可以实现很多强大的功能。

例如,指定多个回调函数:按如下方式复制代码:f1()。然后(f2)。然后(F3);再举一个例子,当出现错误时指定回调函数:复制代码如下:f1()。然后(f2)。失败(F3);而且,它还有一个优点是前面三种方法都没有的:如果一个任务已经完成,并且添加了回调函数,那么回调函数就会立即执行。因此,您不必担心错过事件或信号。这种方法的缺点是比较难写和理解。

更多资讯
游戏推荐
更多+