JS线程与事件循环解析

  JS是单线程,JS代码从上到下依次执行,但是单线程有一个非常大的问题,遇到耗时的任务,后面的任务只能等待它执行完,才能接着执行。比如ajax请求,从服务器上获取数据,本身是耗时的,如果遇到网络波动,就更耗时,只能等待它的返回结果再接着执行后面的任务。如果处在渲染阶段,也会阻塞渲染。

  基于此,JS引入了异步的概念,当遇到耗时的任务,JS将其压入事件队列,先执行后面的任务,等主线程的任务执行完毕,再处理事件队列中的任务。以ajax请求为例,当JS执行到ajsx函数的时候,其实是去告诉浏览器执行http请求,然后立即返回主线程栈执行后面的任务,当浏览器拿到服务器返回数据,将数据传给ajax回调函数,并将回调函数压入到事件队列中。当主线程的任务全部执行完,就会去轮询事件队列,一旦发现事件队列的回掉函数,依次取出放至执行栈中执行;在程序执行过程中,js会一直执行轮询,直到程序结束。

  JS主线程工作流程:JS代码加载完成,创建全局执行环境,至上而下依次执行任务。遇到非异步函数,将创建函数执行环境,函数执行完即销毁,执行下个任务;直到全局执行环境代码执行完毕,执行栈为空。

  JS事件循环队列流程:当执行栈为空,JS会去轮询事件队列,在事件队列取起始位置第一个任务(注册的回调函数)放到执行栈中执行,等回调函数执行完毕,执行栈为空,再次轮询事件队列,步骤如上。在整个程序执行过程中,js会一直轮询事件队列,一有任务就会执行上述过程,该过程称为事件循环。

  注意:所有程序都在执行栈中执行,只有执行栈为空,才有能力执行下一个任务。所以这也要求,回调函数中不能执行太多任务,如果执行太多任务,栈就不为空,也就阻止了下一个任务的执行,造成阻塞。

  promise.then,process.nextTick, setTimeout 以及 setImmediate 的执行顺序:

setImmediate(function(){
    console.log(1);
},0);
setTimeout(function(){
    console.log(2);
},0);
new Promise(function(resolve){
    console.log(3);
    resolve();
    console.log(4);
}).then(function(){
    console.log(5);
});
console.log(6);
process.nextTick(function(){
    console.log(7);
});
console.log(8);

// 3 4 6 8 7 5 2 1

关于优先级:

  每次轮询事件队列,各观察者的优先级为:

  idle观察者》I/O观察者》check观察者

  idle观察者:process.nextTick

  I/O观察者:一般性的I/O回调,如网络,文件,数据库I/O等

扫描二维码关注公众号,回复: 6263243 查看本文章

  check观察者:setTimeout>setImmediate

  注:promise本身不是异步函数 且优先级大于async

    

  

猜你喜欢

转载自www.cnblogs.com/xuxiaoqiangAndHM/p/10903599.html