手机版

理解javascript异步编程

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

第一,异步机制。

JavaScript的执行环境是单线程的,单线程的优点是执行环境简单,不需要考虑资源同步、死锁等恼人的问题,多线程阻塞编程。但缺点是,当一个任务需要很长时间执行时,下面的任务会等待很长时间。在浏览器端,浏览器将暂停,鼠标不会响应。因此,在浏览器端,长时间的操作应该异步执行,以避免浏览器失去响应。异步执行不同于同步执行(程序的执行顺序与任务的排列顺序一致、同步)。每个任务都有一个或多个回调函数。前一个任务完成后,执行回调函数代替后一个任务,后一个任务在前一个任务完成前执行。因此,程序的执行顺序与任务的排列顺序是不一致和不同步的。既然Javascript是单线程的,那么如何异步执行呢?

第二,Javascript线程模型和事件驱动。

JavaScript具有基于事件循环的并发模式。这种模式与C语言和java有很大不同。

运行时的概念。

堆栈调用形成堆栈帧。

函数f(b){ var a=12;返回a b 35}函数g(x){ var m=4;返回f(m * x);} g(21);当函数g被调用时,包含g参数和局部变量的第一帧被创建。当g函数调用f函数时,会创建包含f参数和局部变量的第二个堆栈帧,并将其推到第一个堆栈帧的顶部。当f返回时,顶部堆栈框架元素弹出(只留下g调用)。当g函数返回时,堆栈为空。

堆是一个大的非结构化区域,对象被分配到其中。一个javascript运行环境包含一个信息队列,它是一个要执行的信息列表。每条消息都与一个函数相关联。当堆栈为空时,从消息队列中取出一条消息并进行处理。这个过程包括调用相关的函数(从而生成一个初始化的堆栈框架)。当堆栈再次为空时,消息处理结束。事件循环

事件的名称来自它的实现,通常是这样的:

while(queue . waitformmessage()){ queue . processnextmessage();} queue.waitForMessage同步等待消息。

1.在每条消息被完全处理之前,不会处理其他消息。这样做的好处是,当一个函数无法高级时,只能等待其他函数完成执行(并且可以修改数据的函数操作)。这与c不同,例如,如果一个函数在一个线程中运行,它可以在任何时候停止,并在另一个线程中运行一些其他代码。这种模式的缺点是,如果一条消息需要太长时间才能完成,网络应用程序就无法处理像点击或滚动这样的用户交互。这种浏览器可以缓解这种情况和“脚本运行时间过长”对话框。一个好的做法是保持信息处理的简短,如果可能的话,把一条信息剪成几条信息。2.在网络浏览器中添加消息。事件可以随时添加。事件发生并与事件监控一起绑定到该事件。如果没有事件监视,事件将丢失。就像点击一个元素一样,点击事件被绑定到该元素。当调用setTimeout时,当函数的第二个参数time传入时,一条消息将被添加到队列中。如果队列中没有其他消息,将立即处理该消息。但是,如果有消息,setTimeout的信息将不得不等待其他消息被处理。因此,第二个参数是最小时间,而不是保证时间。3.几个运行环境之间的通信网络工作者或跨域iframe有自己的堆栈、堆和消息队列。两个不同的运行环境只能通过postMessage发送消息进行通信。如果其他运行时侦听消息事件,此方法会将消息添加到其他运行时。永远不要阻挡。

事件模型是javascript的一个有趣属性。与其他语言不同,它从不阻塞。假设浏览器中有一个专门用于事件调度的实例(这个实例可以是一个线程,我们可以称之为事件调度线程),这个实例的工作是一个无休止的循环,从事件队列中获取事件,处理所有与事件相关的回调函数。注意回调函数是在Javascript的主线程中运行,而不是在事件分发线程中运行,这样可以保证事件处理不会被阻塞。通过事件和回调的I/O操作是典型的性能,因此当应用程序等待索引数据库查询或XHR请求的返回时,它仍然可以处理其他事情,如用户输入。

第三,回调。

回调是javascript的基础,函数作为参数传递。如下所示:

f1();F2();F3();如果在f1中执行大量耗时的操作,而f2需要在f1之后执行。程序可以改为回调。如下所示:

函数f1(callback){ settimeout(function(){//f1)大量耗时的任务代码组合成三个结果I,l,you.console.log('这是函数1 ');var i='我',l='爱',y='你';if(callback type of(callback)==' function '){ callback(I,l,y);} }, 50);}函数f2(a,b,c){ alert(a ' ' b ' ' c);console.log('这是函数2 ');}函数f3(){console.log('这是函数3 ');} f1(F2);F3();运行结果:

Is function 3这是function 1我爱你这是function 2这样,我们把同步操作改成异步操作,f1不会阻塞程序运行,相当于先执行程序的主逻辑,再把耗时的操作推迟。回调函数的优点是简单轻量(不需要额外的库)。缺点是每个部分都是高度耦合的,过程会比较混乱,每个任务只能指定一个回调函数。一个操作需要经过几个非阻塞IO操作,每个结果都被回调生成意大利面代码。

operation1(函数(err,result) { operation2(函数(err,result) { operation3(函数(err,result) { operation4(函数(err,Result) {operation 5(函数(err,Result){//做点有用的事})} } })})IV。事件监控。

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

//连接事件句柄的普通非jQuery版本r clickity=document . getelementbyid(' clickity ');clickity . addeventlistener(' click ',function(e){//控制台日志,因为它就像所有现实世界的场景,amirite?console . log(‘唉,有人在按我的按钮……’);});//strong制性的jQuery版本$('#clickity ')。on('click ',function (e) { console.log('唉,有人在按我的按钮……');});您还可以自定义用于监控的事件。对于自定义事件,它属于另一部分。这种方法的优点是容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,并且可以解耦,有利于实现模块化。缺点是整个程序会变成事件驱动,运行过程会变得非常不清晰。

动词(verb的缩写)观察者模式

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

var pubsub=(function(){ var q={ } topics={ },SubId=-1;//发布消息q.publish=function (topic,args) {if(!topics[topic]){ return;} var subs=topics[topic],len=subs.lengthwhile(len - ) { subs[len]。func(topic,args);}退回这个;};//订阅事件q. subscribe=function (topic,func){ topics[topic]=topics[topic]?topics[topic]:[];var token=(SubId)。toString();话题[话题]。push({ token : token,func : func });返回令牌;};返回q;//如果取消订阅,就不会编写、遍历主题,然后通过保存之前返回的token来删除指定的元素})();//触发的事件varf2=函数(topics,data){ console . log(' logging : ' topics ' : ' data);console.log('这是函数2 ');} function f1(){ settimeout(function(){//f1('这是function1 ')的任务代码console.log//发布消息‘done’pubsub . publish(‘done’,‘hello world’);}, 1000);}pubsub.subscribe('done ',F2);f1();上述代码的运行结果是:

实现这个功能有很多方法1日志: done : hello world这是功能2观察者模式,也可以直接借用第三方库。这种方法本质上类似于‘事件监控’(观察者模式非常类似于自定义事件),但明显优于后者。除了事件监控,观察者有很好的解耦,并且有一个消息中心。通过对消息中心的处理,可以很好地监控程序。

不及物动词承诺对象

CommonJS团队成员在Promises/A规范中提出了Promises的概念。承诺逐渐被用作管理异步操作回调的方法,但是由于它们的设计,它们远比这有用。Promise允许我们以同步方式编写代码,并为我们提供代码的异步执行。

函数f1(){ var def=$。递延();SetTimeout(function () {//f1任务代码console.log('这是f1 ');def . resolve();}, 500);return def . promise();}函数f2(){ console.log('这是F2 ');}f1()。然后(F2);上述代码的运行结果是:

这是f1这是f2。以上引用的是jquery对Promises/A的实现,jquery中有一系列的方法,具体请参考:delivered Object。对于承诺,强烈建议阅读你错过了承诺的要点。也有很多实现承诺的第三方库,比如q、蓝鸟、mmDeferred等。Promise(中文:promise)实际上是一个有限状态机,有三种状态:待定、履行和拒绝。其中待定是初始状态,履行和拒绝是结束状态(结束状态表示承诺的生命周期已经结束)。状态转换的关系是:待定-完成,待定-拒绝。随着状态的转换,会触发各种事件(如执行成功和执行失败等。).下一节描述通过状态机对js进行异步编程。

七、状态机。

Promises的本质实际上是通过状态机来实现的,状态机将异步操作与对象的状态变化联系起来。当异步操作结束时,会发生相应的状态变化,然后触发其他操作。相比回调函数、事件监控、发布/订阅等解决方案,更符合逻辑,更容易降低代码复杂度。承诺请参考JS魔堂:分析源代码,理解承诺/A规范。

八、ES6对异步的支持。

这是一项新技术,已成为2015年ECMAScript(ES6)标准的一部分。这项技术的规范已经完成,但是在不同的浏览器中实现是不同的。浏览器中的支持如下。

var f1=new promise(function(resolve,reject){ settimeout(function(){//f1是console.log('这是f1 '))的任务代码;决心(“成功”);}, 500);});函数f2(val){ console.log(val ': ' '这是F2 ');}函数f3(){ console.log('这是F3 ')} f1 . then(F2);F3();Chrome版本43中上述代码的运行结果是:

Isf3这是f1成功:这是F2。以上就是对javascript异步编程的理解和学习。之后,还有相关文章分享。不要错过。

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