手机版

详细解释js的异步编程技术

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

基于基于浏览器的事件轮询机制(以及Node.js中的事件轮询机制),JavaScript经常在异步环境下运行。由于JavaScript本身的语言特性(程序员不需要控制线程/进程),所以解决js中的异步编程非常重要。可以说js开发者在一个完整的项目中是无法面对异步操作的。本文将详细介绍几种经典的JavaScript异步编程序列化方法,并简要介绍ES6提供的Promise顺序执行方法。

一、回调函数

(1)经典回调函数模式:嵌套内联函数

假设我们有一个ajax()方法,它接收一个url参数,向该地址发出异步请求,并在请求的末尾执行第二个参数——一个回调函数:

ajax(url,函数(结果){ console.log(结果);});可以说这个方法是几乎每一个前端开发者都使用的回调函数。使用这种回调机制,开发人员不需要编写如下代码来猜测服务器请求何时返回:

var result=Ajax(URL);setTimeout(函数(结果){ console.log(结果);},400);大家应该都能明白我在这里想说什么。我们设置了一个延迟为400毫秒的计时器,假设我们发送的ajax请求将在400毫秒内完成。否则,我们将操作一个未定义的结果。

但是,随着项目的扩展,一个问题逐渐出现:如果场景要求我们在多个层嵌套回调函数,那么代码将变得难以阅读和维护:

ajax(url0,函数(result0){ ajax(result0.url1,函数(result1){ ajax(result1.url2,函数(result 2){ console . log(result 2)};});});});(2)调用外部函数

为了解决内联回调函数暴露的代码混乱问题,我们引入外部函数调用来解决类似问题:

函数handle2(结果){ console.log(结果);} function handle 1(result){ Ajax(result . URL),function(result){ handle 2(result);});}ajax(url,函数(结果){ handle1(结果);});通过拆分内联函数,调用外部函数的优化方法可以大大简化代码。

二.开发回拨经理

看看现在流行的JavaScript流控制工具,比如Nimble、Step和Seq,我们会学到一个简单的设计模式:异步JavaScript执行流由回调管理器控制。以下是回调管理器的典型关键代码示例:

var Flow={ };//设置下一个方法,调用下一个方法流。next=function () {if (this。stack[0]){//弹出方法栈中的第一个方法,执行this . stack . shift()();}};//设置series方法,接收函数数组,执行flow。series=function (arr) {this。stack=arrthis . next();};//我们可以通过flow . series([function(){//do something console . log(1))来控制传入函数的执行顺序;flow . next();},函数(下一个){//做点什么console . log(2);flow . next();}]);我们初始化了一个流量控制器,并设计了两个函数属性,系列和下一个。在我们编写的业务方法中,通过在方法的末尾调用Flow.next()来依次触发下一个方法。通过执行series方法顺序执行异步函数。这种通过核心控制器管理异步函数调用的方式简化了我们的编程过程,并使开发人员能够将更多的精力投入到业务逻辑中。

三.全球标记控制

(1)简单的计数器控制

也许上面描述的异步方法仍然不能满足实际开发中的业务场景:假设我们有三个方法,A(),B()和C(),A和B没有依赖关系,可以异步进行。但是c必须在a和b都完成后触发。为了满足这个逻辑实现,我们添加了一个全局计数器来控制代码执行流程:

var标志=2;var aValue,bValue函数a(){ aValue=1;旗帜-;c();} function b(){ setTimeout(function(){ Bvalue=2;旗帜-;c();},200);} function c(){ if(flag==0){ console . log(' a和b:' (aValue bValue)之后);} } a();b();我们设置了一个全局变量标志来监控方法a和方法B的完成情况,方法B通过设置200毫秒的定时器来模拟网络环境,最后在方法B执行后成功调用方法C.这样,我们实现了方法a()、b()和c()的依赖调用。

(2)面向数据的控制

上述方案应用于复杂场景时,会出现以下问题:产品已经迭代了多个版本,C方法依赖的方法较多,需要不断更换计数器标志;开发人员在产品迭代期间被替换。当出现以上两种情况时,代码的逻辑就会变得混乱,标志标志能否保持简洁正确很大程度上受产品迭代的影响。因此,我们提出了面向数据的优化和改进。

在实际开发场景中,方法依赖的原因基本上是因为数据依赖。对于上面的简单例子,方法C取决于方法A和方法B的运算结果,而不是标志是否为0。因此,我们可以通过检查从属方法是否完成了数据处理来检查aValue和bValue是否已经完成了c方法中的赋值,而不是检查标记是否已经设置为0:

函数c(){ if(aValue!==未定义的b值!==undefined){ console.log('在a和b: '之后'(aValue b value));}}对于更一般的场景,我们对上述代码进行如下修改:

var check dependency={ };var aValue,bValue函数a(){ aValue=1;checkDependency.a=truec();} function b(){ setTimeout(function(){ Bvalue=2;checkDependency.b=truec();},200);}函数c(){ if(check dependency . a check dependency . b){ console . log('在a和b:' (aValue bValue)之后);} } a();b();有了面向数据的检查方法,以后扩展时,只需要在新增加的方法中增加对checkDependency对象的修改,在C方法中检查对应属性的存在,从而实现异步依赖方法的顺序执行。

四.ES6新方法-—承诺类

为了解决JavaScript中异步方法的复杂性,政府引入了一种统一的控制方法:

var bool=false/* *创建一个新的Promise实例,并将异步执行函数传递给构造函数。*异步函数接受两个参数,它们由Promise传入,对应于由then方法传入的方法。*/var promise=new promise(函数(resolve,Reject) {settimeout(函数(){ if(bool)}//根据执行情况调用resolve和Reject resolve(bool);} else { reject(bool);} },200);});//将Promise.then(函数resolve(result){ console . log(' success ')传递给Promise实例;},函数reject(result){ console . log(' failure ');});上面示例中的代码显示了一个基本的Promise应用程序,也许下面的链式调用在实际场景中更常见:

新承诺(函数(res,rej) {if (/*异步调用成功*/){ res(数据);}else{ rej(错误);}}).然后(函数resolve(result){ console . log(' success ');},函数reject(result){ console . log(' failure ');});如果你对Promise感兴趣,可以在网上搜索资料,继续深入学习!

关于Promise的兼容性,通常web前端的JavaScript代码中不会直接使用Promise(通过caniuse.com网站的查询发现Android4.4不支持Promise)。如果你特别想使用它,你会经常附加一些承诺类库来补充项目中的兼容性;而后端Node.js可以安全地使用Promise类来管理异步逻辑。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:详细解释js的异步编程技术是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。