摘要:从诞生之日起就是一门单线程的非阻塞的脚本语言。这意味着这些线程实际上应属于主线程的子线程。所以严格来讲这些线程并没有完整的功能,也因此这项技术并非改变了语言的单线程本质。函数执行栈和事件队列
浏览器渲染
从耗时的角度,浏览器请求、加载、渲染一个页面,时间花在下面五件事情上:
1.DNS 查询
2.TCP 连接
3.HTTP 请求即响应
4.服务器响应
5.客户端渲染
这里重点讨论第五个部分,即浏览器对内容的渲染,这一部分(渲染树构建,布局和绘制),又可以分为下面的五个部分。
1.处理 HTML 标记并构建 DOM 树。
2.处理 CSS 标记并构建 CSSOM 树。
3.将 DOM 与 CSSOM 合并成一个渲染树。
4.根据渲染树来布局,以计算每个节点的几何信息。
5.将各个节点绘制到屏幕上。
这些并不是本文正文,只是说在完成以上过程之后,整个页面就已经出来了,这个时候浏览器是否就已经处于空闲状态了呢(不考虑动画、交互等处理)?接下来就是本文的重点了。
堆、栈、队列了解重点之前我们先了解一点简单的基础知识,堆、栈、队列;
堆对象被分配在一个堆中,即用以表示一个大部分非结构化的内存区域。
这是在程序运行时需要给对new操作产生的对象分配存储空间,是一个没有特别限制的存储空间。
栈函数调用形成一个栈帧;
栈的特点:先进后出(First in, last out)函数执行栈过程;可以看成是每次函数first运行时,将函数入栈,此时函数中的其他运行函数(second函数)需要再次入栈,执行完该second函数之后,该second函数将会出栈,继而完成first的执行,执行完成后,first将会出栈;
队列是一种和栈不一样的数据结构,类似管道,先进入的将会现出来,和栈是相反的。
event-loopjavascript从诞生之日起就是一门单线程的非阻塞的脚本语言。这是由其最初的用途来决定的:与浏览器交互。
单线程意味着,javascript代码在执行的任何时候,都只有一个主线程来处理所有的任务。
而非阻塞则是当代码需要进行一项异步任务(无法立刻返回结果,需要花一定时间才能返回的任务,如I/O事件)的时候,主线程会挂起(pending)这个任务,然后在异步任务返回结果的时候再根据一定规则去执行相应的回调。
单线程是必要的,也是javascript这门语言的基石,原因之一在其最初也是最主要的执行环境——浏览器中,我们需要进行各种各样的dom操作。试想一下 如果javascript是多线程的,那么当两个线程同时对dom进行一项操作,例如一个向其添加事件,而另一个删除了这个dom,此时该如何处理呢?因此,为了保证不会 发生类似于这个例子中的情景,javascript选择只用一个主线程来执行代码,这样就保证了程序执行的一致性。
当然,现如今人们也意识到,单线程在保证了执行顺序的同时也限制了javascript的效率,因此开发出了web worker技术。这项技术号称让javascript成为一门多线程语言。
然而,使用web worker技术开的多线程有着诸多限制,例如:所有新线程都受主线程的完全控制,不能独立执行。这意味着这些“线程” 实际上应属于主线程的子线程。另外,这些子线程并没有执行I/O操作的权限,只能为主线程分担一些诸如计算等任务。所以严格来讲这些线程并没有完整的功能,也因此这项技术并非改变了javascript语言的单线程本质。
可以预见,未来的javascript也会一直是一门单线程的语言。
那么为了能够很好地提高的脚本的效率,故而设计的时候有一个非常有趣的特性是事件循环模型,与许多其他语言不同,它永不阻塞。 处理 I/O 通常通过事件和回调来执行,所以当一个应用正等待IndexedDB查询返回或者一个 XHR 请求返回时,它仍然可以处理其它事情,如用户输入。
macro task与micro task首先执行script,script被称为全局任务,也属于macrotask;
当macrotask执行完以下,执行所有的微任务;
微任务全部执行完,再取任务队列中的一个宏任务执行。
宏任务包括:script, setTimeout, setInterval, setImmediate, I/O,UI rendering,requestAnimationFrame
微任务包括:process.nextTick(node api), 原生Promise(有些实现的promise将then方法放到了宏任务中),Object.observe(已废弃), MutationObserver
所有的宏任务放在一个宏任务队列(即任务队列),处理完一个宏任务(从sccript开始),将微任务队列(包含当时所有的微任务)压入任务队列(宏任务队列)并执行,之后再取下一个任务队列(宏任务)中的宏任务。
https://juejin.im/post/5b6d58...
https://github.com/ccforward/... 【函数执行栈和事件队列】
https://zhuanlan.zhihu.com/p/...
https://jakearchibald.com/201...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/97048.html
摘要:检查宏任务队列,发现有的回调函数立即执行回调函数输出。接着遇到它的作用是在后将回调函数放到宏任务队列中这个任务在再下一次的事件循环中执行。 为什么会写这篇博文呢? 前段时间,和头条的小伙伴聊天问头条面试前端会问哪些问题,他称如果是他面试的话,event-loop肯定是要问的。那天聊了蛮多,event-loop算是给我留下了很深的印象,原因很简单,因为之前我从未深入了解过,如果是面试的时...
摘要:回调函数任务完成的时候,需要执行哪段代码来处理呢当然是回调函数了。事件处理器和回调函数类似。但是特定的事件处理器在浏览器进入异步事件驱动阶段时就会针对特定的事件注册。当事件对象返回到执行线程时,事件处理器也会同时进入执行栈中执行。 Event Loop(事件轮询)机制是一个经常把人搞晕的东东。我不敢说我完全明白,只是在此谈谈我的浅见。 事件的处理 浏览器是一个事件驱动(event-dr...
摘要:如果执行的准备时间大于了,因为执行同步代码后,定时器的回调已经被放入队列,所以会先执行队列。 showImg(https://segmentfault.com/img/remote/1460000018998584); 阅读原文 浏览器中的事件轮询 JavaScript 是一门单线程语言,之所以说是单线程,是因为在浏览器中,如果是多线程,并且两个线程同时操作了同一个 Dom 元素,...
摘要:事件循环首先来看一段代码运行结果是先输出,然后大概好几秒大于一秒以后依次输出,。原因就在以下这部分代码中原因就是这部分循环的代码执行过程超过了秒。而这个循环是放在里面的。 Event-loop 事件循环 首先来看一段代码 function fn(){ console.log(1) setTimeout(() => { console.log(2) }, 1000) ...
摘要:所以本来快轮到你来办理业务,会因为老大爷临时添加的理财业务而往后推。在执行完同步代码与微任务以后,这时继续向后查找有木有宏任务。所以输出了第二次,等到这两次都执行完毕后才会去检查有没有微任务有没有宏任务。 首先,JavaScript是一个单线程的脚本语言。 所以就是说在一行代码执行的过程中,必然不会存在同时执行的另一行代码,就像使用alert()以后进行疯狂console.log,如...
阅读 2562·2021-09-02 15:40
阅读 1565·2019-08-30 15:54
阅读 1079·2019-08-30 12:48
阅读 3398·2019-08-29 17:23
阅读 1046·2019-08-28 18:04
阅读 3664·2019-08-26 13:54
阅读 606·2019-08-26 11:40
阅读 2390·2019-08-26 10:15