JavaScript Event Loop 浅析

最近在学习Nodejs的过程中深入的了解了异步编程这个概念,为了更好的使用Nodejs,这些概念不可不知。在以前作为一个JavaScript用户的时候,完全是不知道它是怎么运行的,对好些概念也是“知其然不知其所以然”。

对于客户端的JavaScriptNodejs来说其实差距不是很大,这回就从客户端方面来说说Event Loop这个概念吧,算是异步编程的一个切入点吧。其实jQuery的作者 John Resig 在几年前就写了一篇好文章How JavaScript Timers Work,来讲述timer事件在浏览器中是怎样工作的,我也是通过这篇文章才“知其所以然”。

问题场景

先来看看一段代码:

<a href="#" id="doBtn">do something</a>
<div id="status"></div>
<script type="text/javascript">
  void function() {
    var doBtn = document.getElementById('doBtn')
      , status = document.getElementById('status');

    doBtn.onclick = function(e) {
      e.preventDefault();

      status.innerText = 'doing...please wait...';  // 开始啦
      sleep(10000);  // 模拟一个耗时较长的计算过程,10s
      status.innerText = 'done';  // 完成啦
    };
  }();

  function sleep(ms) {
    var start = new Date();
    while (new Date() - start <= ms) {}
  }
</script>

上面代码主要想完成一个功能:按钮被点击时 ------> 显示一个状态告知用户正在干一些事情 ------> 开始干 ------> 事情干完后状态变更为已完成。

看上去没问题,应该是可以工作的,于是在浏览器运行这个页面。可是现实总是残忍的,没有符合预期效果。当点击按钮之后,浏览器就冻结了,用于显示状态的div并没有显示,界面上也没有“doing...”这个提示;经过10s之后,浏览器回过神了,代表耗时较长的计算已经结束,此时用于显示状态的div显示“done”。

究其原因:JavaScript 引擎是单线程的。而此时还有必要再了解下浏览器内核都有哪些主要的常驻线程,才能解上面的疑惑。浏览器内核常驻线程大致包含以下:

  1. 浏览器 GUI 渲染线程
  2. JavaScript 引擎线程
  3. 浏览器定时触发器线程
  4. 浏览器事件触发线程
  5. 浏览器 http 异步请求线程

而 GUI 渲染线程和 JavaScript 引擎线程是互斥的,JavaScript 执行时 GUI 渲染线程是挂起的,页面将停止一切的解析和渲染行为。上面的 3、4、5 类线程也会产生不同的异步事件。看下面这张图就应该比较直观了。

JavaScript-Event-Loop

因为 JavaScript 引擎是单线程的,所以代码都是先压到队列,然后由引擎采用先进先出的方式运行。事件处理函数、timer 执行函数也会排到这个队列中,然后利用一个无穷回圈,不断从队头取出函数执行,这个就是Event Loop

接下来还是继续用图来说明上面的代码为什么没有达到预期效果。

于是结果就只看到了 "done"。

怎样解决?

使用setTimeout(),下面是修改后的onclick事件处理函数:

doBtn.onclick = function(e) {
  e.preventDefault();

  status.innerText = 'doing...please wait...';  // 开始啦
  
  setTimeout(function() {
    sleep(10000);  // 模拟一个耗时较长的计算过程,10s
    status.innerText = 'done';  // 完成啦
  }, 0);  // 0ms delay
};

为什么这样就解决了呢?还是用上面的队列的图来解释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值