js的运行机制
时间:2021-03-04 13:06:43
收藏:0
阅读:0
浏览器线程
js运作在浏览器中,是单线程的,即js代码始终在一个线程上执行,这个线程称为js引擎线程。
但浏览器是多线程的,除了js引擎线程,它还有:
-
UI渲染线程
-
浏览器事件触发线程
-
http请求线程
-
EventLoop轮询的处理线程
……..
这些线程的作用
- js线程用于执行js任务
- UI线程用于渲染页面
- 浏览器事件触发线程用于控制交互,响应用户
- http线程用于处理请求,ajax是委托给浏览器新开一个http线程
- EventLoop处理线程用于轮询消息队列
浏览器中的js任务
- 执行JavaScript代码
- 对用户的输入(包含鼠标点击、键盘输入等等)做出反应
- 处理异步的网络请求
理解js单线程
- 单线程的含义是js只能在一个线程上运行,也就说,js同时只能执行一个js任务,其它的任务则会排队等待执行。
- js是单线程的,并不代表js引擎线程只有一个。js引擎有多个线程,一个主线程,其它的后台配合主线程。
- 多线程之间会共享运行资源,浏览器端的js会操作dom,多个线程必然会带来同步的问题,所有js核心选择了单线程来避免处理这个麻烦。js可以操作dom,影响渲染,所以js引擎线程和UI线程是互斥的。这也就解释了js执行时会阻塞页面的渲染。
js的运行机制
(1)所有同步任务都在主线程上执行,形成一个执行栈。
(2)主线程之外,还存在一个”任务队列”。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
(3)一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
主线程从”任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
简单说,浏览器的两个线程:一个负责程序本身的运行,称为”主线程”;另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为”Event Loop线程”(可以译为”消息线程”)。
宏任务和微任务
事件轮询其实就是轮流询问宏任务队列和微任务队列
执行顺序:
- 先执行同步代码再执行异步代码
- 先执行微任务再执行宏任务
常见宏任务: setTimeout 、setInterva、I/O
常见微任务:process.nextTick(nodejs独有) 、 Promise.then 、catch、finally
例子
由于js是单线程的,代码从上往下依次执行。
- setTimeout是宏任务,放入宏任务队列
- promise构造函数中的代码是同步执行的,但setTimeout是宏任务,又放入宏任务队列,打印promise
- 执行同步代码,打印输出33333,接着执行循环代码,输出1到19999
- 根据执行优先级,即使在打印1到19999时,定时器已经到了时间,也不会去执行setTimeout。若打印完19999,根据宏任务队列先进先出原则,打印11111
- 执行剩下的宏任务,在promise中执行resolve()后才会把回调函数then中的代码放入微任务队列中。此时虽然微任务比宏任务的优先级别高,但此刻正在处理宏任务,最节省资源和快捷的方式是先把当前宏任务执行完毕,于是打印22222
- 最后执行then微任务,打印“成功”
setTimeout(() => {
console.log("11111");
}, 0);
let promise = new Promise(resolve => {
setTimeout(() => {
resolve();
console.log("22222");
}, 0);
console.log("promise");
}).then(value => console.log("成功"));
console.log("33333");
for(let i=0;i<20000;i++) {
console.log(i);
}
//promise
//33333
//0
//...
//19999
//11111
//22222
//成功
评论(0)