美文网首页
理解javascript事件循环

理解javascript事件循环

作者: Meteor__ | 来源:发表于2018-01-22 10:37 被阅读0次

1背景

从敲下第一行“Hello World!”起,我们都无时无刻的使用并接触着事件循环。

去年写react的时候总会遇到设置setState,后面调用值不会改变的问题。会想到是异步的原因,试着延时定时问题得到解决。

    this.setState({status: 1})
    console.log(this.state.status);   //0
    setTimeout(()=>{
        console.log(this.state.status);    //1
    },100)

问题可以解决,所以延时定时解决了之后的很多问题。

后面看到javascript的事件循环,才真正理解了这之中的原理。

2单线程

从学习JavaScript开始,就一直看书和资料说JavaScript是一门单线程的语言。JavaScript到处存在着异步(刚开始认为异步是主线程下开的子线程)是依靠事件循环来实现的。

3同步异步

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

如果计算量大,读写IO请求、Ajax开销大。如果通过同步来获取数据会造成程序阻塞。所以像这种开销大的任务,我们使用异步处理。

所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

4事件循环

bg2014100802.png

根据事件循环图来理解这一段代码

//首先整段代码进入主线程执行
let a= 5;
//同步代码立即执行,输出a=5
console.log(a);
//按钮绑定点击事件,当用户点击按钮事件回调函数进入任务队列,待主线程执行完毕调用该函数
oBtn.onclick(function () {
    a = 10;
    console.log(a, 'click');
})
//当延时定时时间到的时候,回调函数进入任务队列,待主线程执行完毕调用任务队列中的函数。
setTimeout(function () {
    console.log(a,'timeout');
},5000)

5node中的事件循环

Node.js也是单线程的Event Loop,但是它的运行机制不同于浏览器环境。


bg2014100803.png
  • V8引擎解析JavaScript脚本。
  • 解析后的代码,调用Node API。
  • libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。
  • V8引擎再将结果返回给用户。

除了setTimeout和setInterval这两个方法,Node.js还提供了另外两个与"任务队列"有关的方法:process.nextTick和setImmediate。它们可以帮助我们加深对"任务队列"的理解。

process.nextTick方法可以在当前"执行栈"的尾部----下一次Event Loop(主线程读取"任务队列")之前----触发回调函数。也就是说,它指定的任务总是发生在所有异步任务之前。setImmediate方法则是在当前"任务队列"的尾部添加事件,也就是说,它指定的任务总是在下一次Event Loop时执行,这与setTimeout(fn, 0)很像。

process.nextTick(function A() {
  console.log(1);
  process.nextTick(function B(){console.log(2);});
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)
// 1
// 2
// TIMEOUT FIRED

上面代码中,由于process.nextTick方法指定的回调函数,总是在当前"执行栈"的尾部触发,所以不仅函数A比setTimeout指定的回调函数timeout先执行,而且函数B也比timeout先执行。这说明,如果有多个process.nextTick语句(不管它们是否嵌套),将全部在当前"执行栈"执行。

现在,再看setImmediate。

setImmediate(function A() {
  console.log(1);
  setImmediate(function B(){console.log(2);});
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0);

哪个回调函数先执行呢?答案是不确定。运行结果可能是1--TIMEOUT FIRED--2,也可能是TIMEOUT FIRED--1--2。setImmediate与setTimeout不分伯仲。

但在递归中,setImmediate永远优于setTimeout

setImmediate(function (){
  setImmediate(function A() {
    console.log(1);
    setImmediate(function B(){console.log(2);});
  });

  setTimeout(function timeout() {
    console.log('TIMEOUT FIRED');
  }, 0);
});
// 1
// TIMEOUT FIRED
// 2

最后感谢阮一峰老师的文章和张仁阳老师的思路。

相关文章

  • Js事件循环

    列表 JavaScript事件循环 测试金字塔 stub JavaScript事件循环理解 javaScript语...

  • 理解javascript事件循环

    1背景 从敲下第一行“Hello World!”起,我们都无时无刻的使用并接触着事件循环。 去年写react的时候...

  • JavaScript是如何工作的:事件循环和异步编程的崛起 +

    摘要: 深度理解JS事件循环!!! 原文:JavaScript是如何工作的:事件循环和异步编程的崛起+ 5种使用 ...

  • 理解 JavaScript 的事件循环

    随便看技术文章时发现关于事件循环(Event Loop)方面的知识还是很混乱,于是多方查阅了相关资料,在此做下笔记...

  • 2019-11-18-本周学习周报

    学习总览 JavaScript 运行机制渲染引擎JavaScript引擎调用栈事件循环 CSS 盒模型的理解 HT...

  • JavaScript事件循环机制[译]

    如果要学习并理解JavaScript,事件循环可以说是最重要的方面之一。这篇文章简单地对事件循环机制进行了解释。 ...

  • JavaScript事件循环

    事件循环是什么?事实上我把事件循环理解成我们编写的JavaScript和浏览器或者Node之间的一个桥梁。 浏览器...

  • Node探秘之事件循环(1)--几个基本要素

    前言 对于想要真正理解JavaScript工作机制的人,理解JS的事件循环(Event Loop)应当是首当其冲的...

  • JavaScript事件循环

    js是一门单线程的语言,不可能进行多线程编程,异步编程就是多线程编程一种模式,但是我们经常讲到js的异步编程,其实...

  • JavaScript - 事件循环

    前言 JavaScript是一门单线程、非阻塞的脚本语言。 单线程意味着javascript代码在执行的任何时候,...

网友评论

      本文标题:理解javascript事件循环

      本文链接:https://www.haomeiwen.com/subject/ltflaxtx.html