技术 | JavaScript 的 “并发模型”

阅读 802
收藏 41
2017-04-05
原文链接:mp.weixin.qq.com

说到并发应该很多人会想到多线程或多进程,很遗憾JavaScript是单线程的,但是JavaScript也有一个很有趣的东西,可以让你产生在使用多线程的感受,事件循环(Event Loop)提供了一些很有意思的东西,今天我想和大家一起讨论讨论。


"Event Loop是一个程序结构,用于等待和发送消息和事件。(a programming construct that waits for and dispatches events or mes


简单的来说Event Loop就是在程序中跑了两个线程(参考iOS的Event Loop),一个线程负责自身的运行(主线程),一个线程负责主线程与其它线程通信。这样来描述其实很好理解,换到JavaScript的语境中,当你在使用setTimeout时,添加一个任务(task functon),这个任务交给了你看不见的一个线程在处理,同时主线程继续保持自身的运行,当主线程运行结束后,它就会去Event Loop中拿之前你添加的任务,继续执行。


while(queue.waitForMessage()){ 
 queue.processNextMessage(); }


很多时候它都会被如此实现,如果当前没有任何消息时,Event Loop会被挂起,一直等待到waitForMessage同步传来消息。


抛开现今已知的setTimeout,setInterval,nextTick,setImmediate等,HTML5也提供了一个web worker来处理多个运行时,只不过它只有监听postMessage来进行通信。Event Loop 对于JavaScript来说概念性的东西比较多,而使用层面的Api就那么几个,理解这个最好的收益是在于处理Web应用时的设计,可以考虑不阻塞页面的方式,将一些依赖部分添加到Event Loop中等待,其实很常见的一个是Ajax,前端经常是需要用到Ajax来获取数据,这就是一个很经典的场景例子。


甚至你可以根据Event Loop的特点来设计自己的一些业务场景,如果从一个函数的调用形成的堆栈来看:


function f(b){  
   var a = 12;
   return a+b+35; }
function g(x){
   var m = 4;
   return f(m*x); }
g(21);


当函数g被调用时,首先会创建一个堆栈帧,这里会包含g的参数x和g的局部变量m,当g调用f时,第二个堆栈帧被创建,并且置于第一个堆栈帧之上,且包含了f的参数b和局部变量a。当f执行完返回之后,f栈就退出了,接着g开始继续,一直到g返回,g栈退出,这个时候就空了。


大家可以想像一下经常使用的App,特点极其的类似,push完之后进入第二个页面,当第二个页面处理完返回之后,第二个页面栈退出,当然App的栈不会空,因为必然需要一个Root栈。如果你想用Web来处理类似的效果,比如现在我们经常会使用到的vue-router或react-router,基本上都是如此原理来处理。


Event Loop 实际上更像是一个挂起的队列,只有当任务被添加到这个队列中,这个Event Loop才可以说是被激活了,其余时间它应该都一直在等待中。不过在JavaScript中,我们很难可以这么细腻的处理,不过这个特点也可以去处理一些另外的场景,比如在处理Hybrid这样的模式中,App启动时需要去配置一些信息,可能这个页面已经出现,其中有很多处会调用一个方法,这时候,就可以把这些“消息”添加到队列中,等待配置信息成功之后,依次执行。不过这个场景也有一个缺点,就是当一个任务耗时过长,其它任务就需要一直等待了,不过针对这样的缺点,有一些方法可以优化一下,比如将一个耗时过长的任务,分解成多个任务。

 

说了那么多,Event Loop是一个很抽象的概念描述,用它在我们的应用程序中,可以解决很多问题,时不待你,从速理解吧。


你身边如果有朋友对混合领域(跨技术栈)或全栈,编程感悟感兴趣,可以转发给他们看哦,^_^先谢过啦。




更多精彩内容可关注我的个人微信公众号:搜索fed-talk或者扫描下列二维码,也欢迎您将它分享给自己的朋友。

评论