资讯专栏INFORMATION COLUMN

关于浏览器Event Loop

youkede / 3265人阅读

摘要:的宿主最开始本身就是浏览器,处理用户的交互事件。既然是单线程的,那就意味着任务需要排队,只有前一个任务执行完毕,下一个任务才能开始,于是就有了任务队列。事件循环有两种用于浏览上下文的事件循环和用于的事件循环。

最近看到Event Loop这个词出现的频率有点高,于是查阅各方资料在此记录一下。

先不说概念,我们来看段代码:

console.log("script start");

setTimeout(function() {
  console.log("setTimeout");
}, 0);

Promise.resolve().then(function() {
  console.log("promise1");
}).then(function() {
  console.log("promise2");
});

console.log("script end");

复制这段代码到控制台,在Chrome会输出如下结果

Why?

如果想弄清楚原因,就必须得弄清楚今天要提到的概念Event Loop。

运行时概念

函数调用形成了一个栈帧。

function foo(b) {
  var a = 10;
  return a + b + 11;
}

function bar(x) {
  var y = 3;
  return foo(x * y);
}

console.log(bar(7)); // 返回 42

当调用 bar 时,创建了第一个帧 ,帧中包含了 bar 的参数和局部变量。当 bar 调用 foo 时,第二个帧就被创建,并被压到第一个帧之上,帧中包含了 foo 的参数和局部变量。当 foo 返回时,最上层的帧就被弹出栈(剩下 bar 函数的调用帧 )。当 bar 返回的时候,栈就空了。

对象被分配在一个堆中,即用以表示一大块非结构化的内存区域。

队列

一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都关联着一个用以处理这个消息的函数。

在事件循环期间的某个时刻,运行时从最先进入队列的消息开始处理队列中的消息。为此,这个消息会被移出队列,并作为输入参数调用与之关联的函数。正如前面所提到的,调用一个函数总是会为其创造一个新的栈帧。

函数的处理会一直进行到执行栈再次为空为止;然后事件循环将会处理队列中的下一个消息(如果还有的话)。

为什么JavaScript是单线程

稍理解JavaScript的都知道JavaScript是单线程,即同一时间只能处理一件事情。JavaScript为什么不能是多线程呢,这样就可以同时处理多件事情提高效率。
JavaScript的宿主最开始本身就是浏览器,处理用户的交互事件。作为浏览器脚本,它只能一次做一件事情,假如用户点击一个按钮的时候,需要删除一个节点,而另一段代码此时又要添加这个节点,那JavaScript该如何处理,以谁为准?
所以JavaScript在创造之初就考虑到了这点,也决定了它只能是单线程,这是它的核心特征之一。

Event Loop

既然JavaScript是单线程的,那就意味着任务需要排队,只有前一个任务执行完毕,下一个任务才能开始,于是就有了任务队列。如果一个任务耗时很长,下面的任务就得一直等着,明显不太合理,那么能否先把耗时很久的任务先挂起来,先执行后面的任务,等IO设备返回的结果,再去执行之前挂着的任务。

于是任务就可以分两种:同步任务和异步任务

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。

异步任务指的是异步的代码加入到任务队列中,等待主线程通知执行
Event Loop

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop!

Event loop:客户端必须使用本章节中所描述的事件循环,来协调事件,用户交互,脚本,呈现,网络等等。 事件循环有两种:用于浏览上下文的事件循环和用于 worker 的事件循环。

任务队列分为宏任务队列(macro tasks) 和 微任务队列(micro tasks)

如何判断一段代码是加入到宏任务队列还是微任务队列?
每个任务都由特殊任务源来定义。 来自同一个特殊任务源的所有任务都将发往特定事件循环。所以我们可以按照不同的来源进行分类,不同来源的任务都对应到不同的任务队列中

(macro-task 宏任务)来源:I/O, setTimeout + setInterval + setImmediate, UI renderder ···
(micro-task 微任务)来源:Promise ,process.nextTick ,MutationObserver, Object.observe ···
Microtasks are usually scheduled for things that should happen straight after the currently executing script, such as reacting to a batch of actions, or to make something async without taking the penalty of a whole new task. The microtask queue is processed after callbacks as long as no other JavaScript is mid-execution, and at the end of each task. Any additional microtasks queued during microtasks are added to the end of the queue and also processed. Microtasks include mutation observer callbacks, and as in the above example, promise callbacks.

看下完整的执行过程:

• 代码开始执行,JavaScript 引擎对所有的代码进行区分。
• 同步代码被压入栈中,异步代码根据不同来源加入到宏任务队列尾部,或者微任务队列的尾部。
• 等待栈中的代码被执行完毕,此时通知任务队列,执行位于队列首部的宏任务。
• 宏任务执行完毕,开始执行其关联的微任务。
• 关联的微任务执行完毕,继续执行下一个宏任务,直到任务队列中所有宏任务被执行完毕。
•执行下一个任务队列。

参考文档:

并发模型与事件循环

JavaScript 运行机制详解:再谈Event Loop

什么是浏览器的事件循环(Event Loop)?

从 薛定谔的猫 聊到 Event loop

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/103302.html

相关文章

  • 初窥JavaScript事件机制的实现(一)—— Node.js事件驱动实现概览

    摘要:如果当前没有事件也没有定时器事件,则返回。相关资料关于的架构及设计思路的事件讨论了使用线程池异步运行代码。下一篇初窥事件机制的实现二中定时器的实现 在浏览器中,事件作为一个极为重要的机制,给予JavaScript响应用户操作与DOM变化的能力;在Node.js中,事件驱动模型则是其高并发能力的基础。 学习JavaScript也需要了解它的运行平台,为了更好的理解JavaScript的事...

    lavor 评论0 收藏0
  • Event Loop - JS执行机制

    摘要:心塞塞根据规范,事件循环是通过任务队列的机制来进行协调的。等便是任务源,而进入任务队列的是他们指定的具体执行任务回调函数。然后当前本轮的结束,主线程可以继续取下一个执行。 依然是:经济基础决定上层建筑。 说明 首先,旨在搞清常用的同步异步执行机制 其次,暂时不讨论node.js的Event Loop执行机制,以下关于浏览器的Event Loop执行机制 最后,借鉴了很多前辈的研究文...

    muddyway 评论0 收藏0
  • 事件循环机制(event loop

    摘要:了解事件循环机制有助于理解的执行过程,同时这也是面试常见题。那么这个回调函数将在何时由谁执行呢已知是浏览器环境提供的,因此浏览器将对它进行处理,浏览器会在本次事件完成,即计时结束后,将回调函数加入循环队列中,然后等待被加入执行栈执行。 如果有人问JavaScript是什么,也许你会说它是一个单线程、非阻塞、异步、解释型的脚本语言。那么作为一个单线程语言,它是怎么实现非阻塞、异步的?这就...

    tain335 评论0 收藏0
  • Event Loop 其实也就这点事

    摘要:众所周知,是,也就意味着在执行的过程中,是,而这样的特性,正是由一个叫的东西决定的有且仅有一个。无论从工程效率还是用户体验的角度来说,这都是不被允许的一件事情。五秒后,结束计时,将回调函数下放到中。至此,正式引出的概念。 前段时间在网上陆续看了很多关于 Event loop 的文章,看完也就混个眼熟,可能内心深处对这种偏原理的知识有一些抵触心情,看完后也都没有去深入理解。最近在看 Vu...

    PrototypeZ 评论0 收藏0
  • script标签与event loop在W3C规范及览器中的表现

    摘要:浏览器推迟事件直到所有的脚本都处于状态。解析器将处理执行这个脚本。创建这个脚本的解析器的文档有正在阻塞脚本执行脚本元素为等待解析阻塞的脚本的状态,同一时刻只能有一个这样的脚本存在。解析器将一个或多个字符转换为表并处理,这个过程是一个典型的。 前言 本文主要对W3C规范中关于script标签和event loop相关的篇幅做了简单的探讨,针对一些必要的相关概念进行了适当的标注和说明。虽然...

    codergarden 评论0 收藏0

发表评论

0条评论

youkede

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<