js引擎RuntimeCallBack事件循环

Posted 简单的小伙子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js引擎RuntimeCallBack事件循环相关的知识,希望对你有一定的参考价值。

浏览器:
主要功能可以总结为:
展示资源,功能交互。
浏览器内核:
渲染引擎 javascript引擎
渲染引擎:
html、CSS、JavaScript文本以及相应的资源转为图像结果。主要作用解析资源并渲染到屏幕上。
JavaScript是解释性语言,在执行过程中实时进行编译,边编译边执行。js引擎的工作是解析js代码,转换成可执行的机器语言。
js为什么是单线程的?
阻塞与cup空跑是不一样的。阻塞的时候,cup没有进行运算,可以让出cup做一些其他的事情,使用while(true)的时候cup是空跑的,不是阻塞。单核cup同一时刻只能做执行一个事情。
javascript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事情,javascript的单线程与它的用途有关,作为浏览器脚本语言,javascript的主要用途是与用户互动,以及操作dom。这就决定了只能是单线程,否则会带来很复杂的同步问题,比如,假定javascript同时有两个线程,操作同一个dom一个是在这个节点上添加内容,一个是删除这个节点,浏览器这个时候就不一定知道应该以哪个为准。
进程:
是cpu分配资源的最小单位(是能拥有资源和独立运行的最小单位)。
线程:
是cpu调度的最小单位,线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程。
自己的理解是一个进程相当于是一个程序App,一个线程相当于是程序App中的一个功能。
浏览器是多进程的,
放在浏览器中,每次打开一个tab界面,其实就是新开了一个进程,在这个进程中,还有ui渲染线程,js引擎线程,http请求线程,
最新的Chrome进程架构大概是这个样子
浏览器进程:主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
渲染进程:核心任务是将HTML、CSS、和javascript转为用户可以与之交互的网页,排版引擎Blink和javascript引擎V8都是运行在该进程中,一般情况下,chrome会为每个Tab标签创造一个渲染进程,处于安全考虑,渲染进程都是于宁在沙箱模式下。
• GPU 进程。其实,Chrome 刚开始发布的时候是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制,这使得 GPU 成为浏览器普遍的需求。最后,Chrome 在其多进程架构上也引入了 GPU 进程。
• 网络进程。主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
• 插件进程。主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。
执行栈与事件队列:
当脚本第一次运行的时候,js引擎会解析这一段代码,并将其中的同步代码按照执行顺序加入到执行栈中,然后开始重头执行(详情请观看执行上下文栈)。这是同步代码的执行。
事件队列:
js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起,继续执行栈中的其他任务。当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的一个队列,这个我们称之为事件队列,被放入事件队列不会立刻执行其回调。而是等待当前执行栈中的所有任务都执行完毕,主线程处于闲置状态时,主线程会查询事件队列里是否有任务,如果有的话,那么主线程就会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈,中,然后执行其中的同步代码,如此这样就形成了一个循环,这个就是事件循环。
图中的stack表示我们所说的执行栈,web apis则是代表一些异步事件,而callback queue即是事件队列。
宏任务和微任务:
异步任务分为分为微任务和宏任务。
• Event Loop是由javascript宿主环境(像浏览器)来实现的;
• WebAPIs是由C++实现的浏览器创建的线程,处理诸如DOM事件、http请求、定时器等异步事件;
• JavaScript 的并发模型基于"事件循环";
• Callback Queue(Event Queue 或者 Message Queue) 任务队列,存放异步任务的回调函数
属于宏任务的事件:

这个执行过程是:当 当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件,同一次循环中,微任务永远在宏任务之前执行。
//同步:a,b。a执行完之后才能执行b。同步里面分为阻塞 非阻塞 I/O多路复用。
//异步:a还没有执行完的时候,就可以开始执行b. 宏任务、微任务。

    console.log(1);
,0);
new Promise(function(resolve,reject)
    console.log(2)
    resolve(3)
).then(function(val)
    console.log(val);
)
结果为:
2
3
1

js中的EventLoop、宏任务、微任务 这个上面的函数例子非常棒,可以多借鉴下。
• 先执行同步函数
• 微任务队列优先于宏任务队列执行;
• 微任务队列上创建的宏任务会被后添加到当前宏任务队列的尾端; 应当注意点
• 微任务队列中创建的微任务会被添加到微任务队列的尾端; 应当注意下
• 只要微任务队列中还有任务,宏任务队列就只会等待微任务队列执行完毕后再执行; 应当注意下
• 只有运行完 await 语句,才把 await 语句后面的全部代码加入到微任务行列;
• 在遇到 await promise 时,必须等 await promise 函数执行完毕才能对 await 语句后面的全部代码加入到微任务中;
• 在等待 await Promise.then 微任务时:
• 运行其他同步代码;
• 等到同步代码运行完,开始运行 await promise.then 微任务;
• await promise.then 微任务完成后,把 await 语句后面的全部代码加入到微任务行列;
参考:
详解JavaScript中的eventloop(事件循环)机制
微任务、宏任务与EventLoop
js中的EventLoop、宏任务、微任务
回流重绘:
布局与绘制:
当浏览器生成渲染树以后,就会根据渲染树来进行布局(也可以叫做回流)。这一阶段浏览器要做的事情就是要弄清楚各个节点在页面中的确切位置和大小。通常这一行为叫做"自动重排",
布局流程的输出是一个"盒模型",它会精确的捕获每个元素在视口内的确切位置和尺寸,所有相对测量值都将转换为屏幕上的绝对像素。布局完成后,浏览器就会立即发出"Paint Setup"和"Paint"事件,将渲染树转换成屏幕上的像素。
回流:
计算DOM节点在设备口内的确切位置和大小,这个计算阶段就是回流。

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Critial Path: Hello world!</title>
  </head>
  <body>
    <div style="width: 50%">
      <div style="width: 50%">Hello world!</div>
    </div>
  </body>
</html>

第一个div将节点的显示尺寸设置为视口宽度的50%,第二个div将其尺寸设置为父节点的50%,而在这回流这个阶段,我们就需要根据视口具体的宽度,将其转为实际的像素值。
重绘:
将渲染树的每个节点都转为屏幕上的实际像素,这个阶段就叫做重绘节点。
何时发生回流重绘:
根据改变的范围和程度,渲染树中或大或小的部分需要重新计算,有些会改变触发整个页面的重排,比如,滚动条出现的时候或者修改了根节点。
页面一开始渲染的时候,
浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
添加或删除可见的DOM元素
元素的位置发生变化
元素的尺寸发生变化(包括外边框、内边框、边框大小、高度和宽度等)
内容发生变化,比如文本变化或者图片被另一个不同尺寸的图片代替
元素字体大小变化
激活css伪类

一些常用,且会导致回流的属性和方法:
clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft
scrollWidth、scrollHeight、scrollTop、scrollLeft
scrollIntoView()、scrollIntoViewIfNeeded()
getComputedStyle()
getBoundingClientRect()
scrollTo()

一下情况发生重绘而不发生回流:
当页面中元素样式的改变并不影响它在文档流中的位置是(例如:color、background-color、visibility),浏览器会将新样式赋予给元素并重新绘制它,这个过程重绘不会回流。
注意:回流一定会触发重绘,但是重绘不一定会触发回流。
回流比重绘代价要高。
参考:
阿离王-前端分享----何时发生回流重绘:link

以上是关于js引擎RuntimeCallBack事件循环的主要内容,如果未能解决你的问题,请参考以下文章

js引擎RuntimeCallBack事件循环

js引擎RuntimeCallBack事件循环

在nodejs中事件循环分析

JavaScript 事件循环

Node.js 事件循环

javascript事件环(EventLoop)