球速体育平台-球速(中国)



球速体育平台-球速(中国)

浅谈javascript事件循环机制

发布于: 2018-07-06    浏览: 2269    作者:Wu


事件(jiàn)的处理


浏览器是一个事件驱动(event-driven)架构(gòu)的软(ruǎn)件。它的(de)UI线程中会不断(duàn)产生用户事件。但是(shì)处理事件的JavaScript是单(dān)线程(chéng)执(zhí)行的,这是一个浏(liú)览器环境下难以改变的现状(HTML5 Web Works没有从本质上改(gǎi)变这个(gè)模型(xíng))。这意味着:在JavaScript处理(lǐ)某个(gè)任务(执(zhí)行某(mǒu)段代码(mǎ))过(guò)程(chéng)中,如果产生了用户事件,它不会立即被处理。那这种情况该怎么办呢?



浏览器维护了一个“任务(wù)队列”(一个优先(xiān)队列数据结构(gòu)),它是一个浏览(lǎn)器进程资源。每当(dāng)UI线程产生(shēng)一(yī)个(gè)事件,事件对(duì)象就被当做任务放入任务队列(liè)中(enqueue)。当JavaScript执行线(xiàn)程(chéng)空闲的时(shí)候,队(duì)列中的(de)一(yī)个(gè)任务就会被送往JavaScript执行线程(dequeue),进(jìn)行(háng)相应的处理。
这个enqueue和(hé)dequeue的机制(zhì)就是“Event Loop”。

但是,不仅用户事件可以被Event Loop机制处理,还能更多(duō)的(de)东西是依赖这个机(jī)制的(de)。


异步IO的处理


如果(guǒ)没(méi)有(yǒu)异步(bù)的理(lǐ)念,这个世界会完全不同(tóng):一个(gè)耗时的I/O操作(例如HTTP请求)会(huì)导(dǎo)致JavaScript执行(háng)线程等待,而后续的操作得不到执行(háng)。这种情况(kuàng)下,一(yī)个耗时的服务器端(duān)数据库操作http请求,会(huì)让JavaScript执行线(xiàn)程阻塞,浏览(lǎn)器将长期处于假死状(zhuàng)态,在此期间,其他后续操作(包括用户的交互事件)得不到响应。

好在(zài)浏览器不是单线程的。它(tā)可以(yǐ)(但不是必须)让这(zhè)些I/O任务让其他线程来(lái)托管(guǎn),这样(yàng)就形成了(le)一个(gè)执行任务(wù)的线程(chéng)池。但是这些任务的结果总归要回到JavaScript执行线(xiàn)程上处理,于是这些(xiē)任务也被放到任务队列中(zhōng):需要被托管的任务被放入队列(liè)中(enqueue),已(yǐ)完成的任务(wù)会(huì)被从(cóng)队列中一个个取(qǔ)出(dequeue),回(huí)到(dào)JavaScript执(zhí)行线程执行回调。在这(zhè)些(xiē)耗时(shí)的I/O任务(wù)被(bèi)托(tuō)管的时候,JavaScript执行线程可以执行其他(tā)代码。

在Node中,这个(gè)过程是类似的。本(běn)文不表。

这(zhè)便是异步的原(yuán)理了。我(wǒ)们看到它同样依赖Event Loop的机(jī)制(zhì)。


定时器


浏览器的全局对象window提供(gòng)了两个方法(fǎ),setTimeout和setInterval。这(zhè)两个(gè)方法其实是调用了浏览器的API,将(jiāng)一个任(rèn)务移除出(chū)JavaScript执行线程中(zhōng),延时处理。

我们现在马上可以反应过来:这(zhè)个将要被延时的任务同样(yàng)是放到了任务队(duì)列中。在一次Event Loop过程中,它会优先(xiān)将(jiāng)该时间点(diǎn)下已经(jīng)到时的延时任务移除出队(duì)列,放(fàng)入JavaScript执行线程中。这意味着(zhe),任务队列是一个优先队列(liè)。

但是由于(yú)JavaScript执行线程的执(zhí)行时间(jiān)是不确定的,所以这个延时只是一个大体的值(zhí),它取决于JavaScript执行线程的执(zhí)行(háng)时间。


回调函(hán)数


任务完成的时候(hòu),JavaScript需要执行(háng)哪(nǎ)段代码(mǎ)来处理呢?当然是(shì)回调函数了。

但是不免奇(qí)怪的一(yī)点就是:JavaScript中怎(zěn)么(me)知道要执行(háng)的是哪个回调函(hán)数呢?答案(àn)就是:任务被(bèi)放(fàng)入任务(wù)队(duì)列的(de)时候,该任务的回调函(hán)数会被注册(注册到什么地(dì)方?需要进(jìn)一步(bù)探(tàn)究(jiū))。这样,当(dāng)特定任务完成的时候,任务(wù)结果和回调(diào)标记会返回给(gěi)JavaScript执行线程,进入(rù)执行栈。


事件处理器


与其他任务不同,事件并不是由JavaScript执行(háng)线(xiàn)程发出(chū)的,而是从UI线程(chéng)中发出的。

事件(jiàn)处理器和回调函数类(lèi)似(sì)。但是特定的事件(jiàn)处理器在浏览器进入异步事件驱动阶段时(shí)就会(huì)针对特定的事件注册。当事件对象返回到JavaScript执行线程时,事件处(chù)理器也会同时进入执行(háng)栈中执行。


 ——本文并非(fēi)原创,如有侵权(quán)请联系管理(lǐ)员删(shān)除。

在线客(kè)服

售前咨询

售后服(fú)务

投(tóu)诉/建议

服务(wù)热线
0731-83091505
18874148081

球速体育平台-球速(中国)

球速体育平台-球速(中国)