我爱编程

理解浏览器和node.js中的Event loop事件循环

2018-03-26  本文已影响0人  reneetsang

大家都知道,javascript是一门单线程语言,因此为了实现主线程的不阻塞,Event Loop这样的方案应运而生。

浏览器和node中Event loop并不一样,浏览器的Event loop是在HTML5中定义的规范,而node中则由libuv库实现。

浏览器中的Event loop

整个最基本的Event Loop如图所示:

evenloop.png

具体过程:

  1. 浏览器中,先执行当前栈,执行完主执行线程中的任务。

  2. 取出Microtask微任务队列中任务执行直到清空。

  3. 取出Macrotask宏任务中 一个 任务执行。

  4. 检查Microtask微任务中有没有任务,如果有任务执行直到清空。

  5. 重复3和4。

整个的这种运行机制又称为Event Loop(事件循环)

例子

了解浏览器的Event loop后,查看下面例子,猜测浏览器是怎么输出的

console.log(1);
console.log(2);
setTimeout(function(){
  console.log('setTimeout1');
  Promise.resolve().then(function(){
    console.log('Promise')
  })
})
setTimeout(function(){
  console.log('setTimeout2');
})

//浏览器输出:1 2 setTimeout1 Promise setTimeout2

node中的Event loop

  1. timers:执行setTimeout() 和 setInterval()中到期的callback。
  1. I/O callbacks:上一轮循环中有少数的I/Ocallback会被延迟到这一轮的这一阶段执行
  1. idle, prepare:队列的移动,仅内部使用
  1. poll:最为重要的阶段,执行I/O callback,在适当的条件下会阻塞在这个阶段
  1. check:执行setImmediate的callback
  1. close callbacks:执行close事件的callback,例如socket.on("close",func)
node-evetloop.png

例子

查看下面例子加深对event loop的理解

在node执行下面代码,发现每次执行先后顺序不一样,因为node需要启动时间,执行过程中setTimeout可能到时间了也可能没到时间,所以这个先后顺序取决于node的执行时间。

setTimeout(function(){
  console.log('timeout')  
})
setImmediate(function(){
  console.log('immediate')
})

i/o操作阶段完成后,会走check阶段,所以setImmediate会优先走

let fs=require('fs');
fs.readFile('./1.log',function(){
  console.log('fs');
  setTimeout(function(){
    console.log('timeout')
  })
  setImmediate(funciton(){
     console.log('setTimmediate')          
  })
})

nextTick应用场景

function Fn(){
  this.arrs;
  process.nextTick(()=>{ //根据nextTick的特性,可以先赋值,再在下一个队列中使用
    this.arrs();
  })
}
Fn.prototype.then=function(){
  this.arrs=function(){console.log(1)}
}
let fn=new Fn();
fn.then();

//注意:nextTick千万不要写递归,不然会造成死循环。可以放一些比setTimeout优先执行的任务

总结

上一篇 下一篇

猜你喜欢

热点阅读