手机版

深入解释JS异步处理的演化历史

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

前言

Javascript是单线程语言,这意味着一次只能完成一个任务。如果有多个任务,它们需要排队等待处理。如果一个任务需要很长时间,那么后面的任务必须排队等待,这极大地影响了整个程序的执行。为了解决这个问题,javascript语言将任务分为两种模式:

同步:我们打开网站时,网页的页面骨架渲染和页面元素渲染是同步的一大任务。异步:当我们浏览新闻时,加载图片或音乐等占用大量资源且耗时较长的任务是异步任务。本文重点介绍了javascript近两年的发展,主要介绍了异步处理的演进历史。目前,在javascript异步处理中,有几种方式:

回收

回调函数是最早解决异步编程的方法。无论是常见的setTimeout还是ajax请求,事情都是以回调的形式在固定时间执行的。

//common:settimeout settimeout(function callback(){ console . log(' aa ');}, 1000);//ajax请求Ajax (URL,function callback(){ console . log(' Ajax success ',RES);})通常,回调函数作为参数传递到函数中,并在适当的时候调用和执行。回调函数的优点是简单,易于理解和实现,但有一个致命的缺点,就是容易出现callback地狱,即嵌套使用多个回调函数。它导致代码可读性和可维护性差,并且只能处理回调中的异常。

Ajax (URL,()={//todo Ajax (URL 1,()={//todo Ajax (url2,()={//todo})})})事件监视

事件监控采用事件驱动模式。事件的执行不依赖于代码的顺序,而是依赖于事件的发生。

假设有两个函数为f1 (jQuery)绑定了一个事件。当f1函数中出现成功事件时,函数f2:被执行

f1 . on(‘成功’,F2);覆盖f1:

函数f1(){ajax(url,()={//todof 1 . trigger(' success ');//触发成功事件执行f2函数})}事件监控的方式简单易懂,可以绑定多个事件,每个事件可以指定多个回调函数,可以“解耦”,有利于模块化。缺点是整个程序会变成事件驱动,运行过程会变得非常不清晰。阅读代码时,很难看到主要流程。

发布订阅

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

//使用jquery插件实现//首先,f2从消息中心订阅成功事件jQuery.subscribe('success ',F2);//重写f1: functionf1 () {Ajax (URL,()={//todo query . publish(' success ');//执行f1后,向jQuery发出成功事件执行f2函数})}//执行F2后,可以退订jQuery。取消订阅(“成功”,F2)。这种方法在本质上类似于事件监控,但是我们可以通过消息中心检查每个信号有多少信号以及有多少用户。

承诺

**Promise**是CommonJS工作组提出的标准,可以得到异步操作的消息,也是异步处理中常见的解决方案。Promise的出现主要是解决回调地狱,支持多个并发请求,获取并发请求的数据,解决异步问题。

让p=newpromise ((resolve,reject)={//做一些异步操作settimeout(()={ let num=parse int(math。random()* 100);if(num 50){ resolve(' num 50 ');//如果数字大于50,调用成功函数,将状态改为Resolved } else { reject(' num 50 ');//否则,调用失败函数,将状态改为拒绝}},10000)});p . then((RES)={ console . log(RES);}).catch((err)={ console . log(err));})Promise有三种状态:等待待定、成功实现、失败拒绝;一旦状态改变,就不会再改变,并且会在创建Promise对象后立即执行。等待状态可以改变为满足状态,并将值传递给相应的状态处理方法,或者可以改变为拒绝状态,并传递失败信息。在任何情况下,都会调用Promise对象的then方法(then方法包含两个参数:onfulfilled和onrejected,这两个参数都是Function。当承诺状态满足时调用已完成的方法,当承诺状态被拒绝时调用已弹出的方法)。

需要注意的是,Promise.prototype.then和Promise.prototype.catch方法返回一个Promise对象,因此可以在链中调用,如下图所示:

许诺的方法:

答应我。all(可重复):谁执行得慢,谁就执行回调。返回一个promise对象,只有当iterable中的所有promise对象都成功时,才会执行该对象。一旦iterable中的promise对象无法执行,它将触发该对象的失败。对象触发成功后,会把一个包iterable中所有承诺返回值的数组作为成功回调的返回值,顺序与iterable的顺序一致;如果这个新的promise对象触发了失败状态,它将把在iterable中触发失败的第一个promise对象的错误消息作为它的失败错误消息。Promise.all方法通常用于处理多个Promise对象的状态集合。答应我。比赛(可重复):回调将被执行,无论哪个更快。可重复参数中任一子承诺成功或失败后,父承诺会立即调用父承诺绑定的对应句柄,以子承诺的成功返回值或失败明细作为参数,返回承诺对象。承诺。拒绝(错误)和承诺。解决(错误)发生器/产量

Generators是ES6提供的异步解决方案,它最大的特点是可以控制函数的执行。可以理解为内部封装了很多状态的状态机,也是一个测力计对象生成函数。发电机功能的特点:

函数关键字和函数名之间有一个星号;函数体内部使用Yield表达式定义不同的内部状态;通过yield暂停函数,然后启动函数,每次返回yield表达式的结果。Next可以接受参数,这样就可以在函数运行的不同阶段从外到内注入不同的值。下一步返回一个包含value和done的对象,其中value表示迭代的值,后者表示迭代是否完成。例如:

函数* createiterator(x){ let y=yield(x 1)let z=2 *(yield(y/3))return(x y z)}//生成器可以像普通函数一样调用,只是它将返回一个迭代器let iterator=createiterator(4);console . log(iterator . next());//{value:5,done : false } console . log(iterator . next());//{value:NaN,done : false } console . log(iterator . next());//{value:NaN,done:true }让迭代器1=createIterator(4);//返回迭代器//next参数console . log(iterator 1 . next());//{value:5,done : false } console . log(iterator 1 . next(12));//{value:4,done : false } console . log(iterator 1 . next(15));//{value:46,done:true}代码分析:

当没有参数时,next的值返回NaN;传递参数时,作为上一个yeild的值,第一次使用next时,传递参数无效,只有第二次启动时才有效。第一次执行next时,函数会在yeild(x ^ 1)中挂起,所以返回4 ^ 1=5;第二次执行next时,传入的12是最后一个yeild表达式的值,所以y=12,返回值为12/3=4;第三次执行next时,传入的15是最后一个yeild表达式的值,所以z=30,y=12X=4,返回30 12 4=46 sync/await

新异步/等待

ES7中提出的Async/await是javascript中异步处理的最终解决方案。

异步本质上是生成器函数的语法糖。与发电机相比,改进如下:

内置执行器:Generator函数必须由执行器执行,而async函数有自己的执行器。其调用方式与普通函数完全相同,无需调整下一个方法;更好的语义:async意味着定义异步函数,而await意味着其背后的表达式需要等待,这比*和yeild更有语义;适用性更广:co模块规定yield命令后面只能跟Thunk函数或Promise对象。异步函数的等待命令后面可以跟Promise或原始类型的值;Promise:async函数的返回值是Promise对象,比Generator函数返回的Iterator对象更方便,可以直接用then()方法调用。语法分析

异步语法

用于定义异步函数,并自动将函数转换为promise对象。然后可以用来添加回调,其内部返回值用作然后回调的参数。

async函数f(){返回“hello async”;}f()。然后((res)={//通过then添加回调,内部返回的res用作回调的参数console . log(RES);//hellaoasync})在异步函数内部可以使用await,它返回的promise对象必须等到内部执行完await命令之后的promise对象,然后才会执行回调。

const delay=function(超时){ return new Promise(function(解析){return setTimeout(解析,超时));});}async函数f(){ wait delay(1000);等待延期(2000年);返回“完成”;}f()。然后(RES=console . log(RES));//打印前需要等待3秒:await表示异步等待,用于暂停异步函数的执行。只能在异步函数和promise中使用,在promise之前使用时,表示等待promise完成并返回结果。

async function f(){ return await 1//await后面没有一个promise,它也会转换成一个Promise,可以立即解析};f()。然后(res=console.log('处理成功',res))//打印输出:处理成功1。catch(err=console.log('处理被拒绝',err))////打印输出:promise {resolved 3360 undefined}错误处理

如果在wait之后发生异步错误,这相当于async返回的promise对象被拒绝,那么catch的回调函数将接收到该错误。应当注意,只要异步功能中的一个等待处于拒绝状态,后续的等待就不会被执行。

让一个;Asyncfunction f () {awaitpromise。拒绝('错误')a=await 1//await 1未执行}err()。然后(res=console.log(a))如何处理呢,可以把第一个await放在try/catch中,遇到函数的时候,可以抛出一个错误,执行下来。

异步函数f(){ try { await Promise . reject(' error ');}catch(错误){ console.log(错误);}返回等待1} f()。然后(RES=console.log ('success ',res))//成功打印出1。如果有多个wait进程,可以统一放在try/catch模块中,async可以使try/catch进程同时出现同步和异步错误。

摘要

通过以上六种常见的javascript异步处理方法,我们可以看出async/await可以说是最终的异步解决方案。最后,让我们看看异步/等待最常用的场景:

如果一个业务需要很多异步操作,并且每一步都取决于上一步的执行结果,这里采用不同的延迟:

//首先定义一个延迟函数函数delay(time){ return new promise(resolve={ settimeout(()=resolve(time),time);});}//实现延迟(500)。然后(结果={returndelay (result1000)})。然后(结果={returndelay (result2000)})。然后(结果={ console . log(result)//3500 ms后打印3500)。catch(error={ console . log(error)})//用async实现async函数f(){ const R1=等待延迟(500) const r2=等待延迟(r1 1000) const r3=等待延迟(r2 2000)返回r3}f()。然后(res={ console.log(res)})。catch(err={ console.log(err)}),可以看到,很多随后被用来进行链式调用,这使得代码变得冗长而复杂,没有语义。Async/await首先使用同步的方法编写异步,使得代码清晰直观,并且使得代码语义化,使得代码执行的顺序一目了然。最后,async函数自带执行器,执行时不需要手动加载。

摘要

以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。谢谢你的支持。

版权声明:深入解释JS异步处理的演化历史是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。