javascript基础修炼(5)—Event Loop

开发者的javascript造诣取决于对【动态】和【异步】这两个词的理解水平。

一. 一道考察异步知识的面试题

题目是这样的,要求写出下面代码的输出:

setTimeout(() => {
  console.log(1)
}, 0)
new Promise((resolve, reject) => {
  console.log(2)
  for (let i = 0; i < 10000; i++) {
    i === 9999 && resolve()
  }
  console.log(3)
}).then(() => {
  console.log(4)
})
console.log(5)

如果没有详细钻研过异步队列,答对的可能性很低。题目的考察点很明确,就是javascript中最核心的特点之一的【异步】,了解了原理以后,你就会明白javascript中声称的“无阻塞”并不是完全成立的,通过一些小办法就可以让setTimeout( )的回调永远都无法被执行,尽管这看起来除了满足整蛊需求以外并没有什么明显的实用价值。

对Event Loop的理解,带给开发者的是对代码整个生命周期更精细的控制能力,尽管在依赖于SPA框架的开发中你几乎不会用到它们。

二. Event Loop的原理

(上图来自下面推荐的这篇博文)

【极力推荐文章】

https://github.com/nswbmw/node-in-debugging/blob/master/3.6%20Event%20Loop.md

并不是笔者偷懒不想写这一节,而是在读过了这篇教程以后,自认为除非是剖析更底层的libuv的原理,否则仅就理解Event Loop而言,笔者自己认为不会比这篇写的清晰。

三. 解析最后一题

上文中给出了从简单到复杂共6道题来供读者自检,算是非常贴心了,本文中针对最后一题进行一些讲解。你会发现只要理解了Event Loop 的基本原理后,分析这类代码基本就是一个【完形填空】的过程

题目如下:

setImmediate(() => {
  console.log(1)
  setTimeout(() => {
    console.log(2)
  }, 100)
  setImmediate(() => {
    console.log(3)
  })
  process.nextTick(() => {
    console.log(4)
  })
})
process.nextTick(() => {
  console.log(5)
  setTimeout(() => {
    console.log(6)
  }, 100)
  setImmediate(() => {
    console.log(7)
  })
  process.nextTick(() => {
    console.log(8)
  })
})
console.log(9)

题目分析:

为了方便分析,先做代码分块:

将代码块放入事件循环:

分析:

这里有必要说明一下Fn2的位置,文中并没有明确提及同步代码执行完毕后进入异步队列时会先经历Tick阶段,就图示而言,每一个宏观任务阶段之间都会检查Tick队列(你也可以理解为每次函数的调用栈被清空的时候会检查一次Tick队列),那么Fn2的待执行时序也就很好理解了。为了方便分析,将console.log(n)相关的方法称为cln

接下来看一下当执行至Fn2时发生的事情:

分析:

Tick队列中的process.nextTick( )回调会直接加入Tick队列(此处就可以实现篇头讲到的阻塞事件循环)。另外讲一下CL6这个回调,它上面绑定了一个100ms的定时器,在后续的TimersIO Polling中都会检查倒计时是否到期,到了就执行,没到就等下一次TimersIO Polling阶段再检查。从上例来看,推迟100ms的CL6在没有其他干扰的情况下几乎一定会在N个event loop以后才被执行。

同样的道理来拆分一下Fn1:

分析:

CL6CL2先开始计时,所以倒计时100ms先到,当然这是N个事件循环以后的事情了。

所以从上面的时序就可以看到输出的结果:9 5 8 1 7 4 3 6 2

【思考题】:

外加一个思考题,如果上例中CL6CL2的延迟都是0,结果是怎样的呢?

四. requestAnimationFrame

requestAnimationFrame()很多时候会被拿来和setTimeout()作对比,这个API是浏览器环境下为了实现高性能帧动画而设计的,它的主要目的是为了让浏览器的重绘能够配合显示设备的刷新率而去掉不必要的性能开销,常见的显示设备刷新率为60Hz,相当于你每1000/60≈16.7ms只能看屏幕一眼,得到的信息都是依靠这些离散画面的视觉暂留拼凑起来的,那如果动画元素在你看屏幕的时间间隔中像素位移过大的话,看起来就会是一卡一卡的,也就是平时常说的“丢帧”,从Event Loop的角度来讲的话,将其近似理解为setTimeout(fn, 1000/刷新率)就可以了。

原文地址:http://blog.51cto.com/13869008/2175086

时间: 2024-10-13 12:02:53

javascript基础修炼(5)—Event Loop的相关文章

javascript基础修炼(7)——Promise,异步,可靠性

开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. 一. 别人是开发者,你也是 Promise技术是[javascript异步编程]这个话题中非常重要的,它一度让我感到熟悉又陌生,我熟悉其所有的API并能够在编程中相对熟练地运用,却对其中原理和软件设计思想感到陌生,即便我读了很多源码分析和教程也一度很难理解为什么Promise这样一个普通的类能够实现异步,也曾尝试着去按照Promise/A+规范来编写Promise,但很快便陷入了一种更大的混乱之中.直到我接触到一些软

javascript基础修炼——一道十面埋伏的原型链面试题

javascript基础修炼--一道十面埋伏的原型链面试题 在基础面前,一切技巧都是浮云. 题目是这样的 要求写出控制台的输出. function Parent() { this.a = 1; this.b = [1, 2, this.a]; this.c = { demo: 5 }; this.show = function () { console.log(this.a , this.b , this.c.demo ); } } function Child() { this.a = 2;

javascript基础修炼(2)——What‘s this(上)

javascript基础修炼(2)--What's this(上) 开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. [TOC] 一.this是什么 this是javascript关键字之一,是javascript能够实现面向对象编程的核心概念.用得好能让代码优雅高端,风骚飘逸,用不好也绝对是坑人坑己利器.我们常常会在一些资料中看到对this的描述是: this是一个特殊的与Execution Contexts相关的对象,用于指明当前代码执行时的Execution

javascript基础修炼(8)——指向FP世界的箭头函数

一. 箭头函数 箭头函数是ES6语法中加入的新特性,而它也是许多开发者对ES6仅有的了解,每当面试里被问到关于"ES6里添加了哪些新特性?"这种问题的时候,几乎总是会拿箭头函数来应付.箭头函数,=>,没有自己的this , arguments , super , new.target ,"书写简便,没有this"在很长一段时间内涵盖了大多数开发者对于箭头函数的全部认知(当然也包括我自己),如果只是为了简化书写,把=>按照function关键字来解析就好了

javascript基础修炼(10)——VirtualDOM和基本DFS

1. Virtual-DOM是什么 Virtual-DOM,即虚拟DOM树.浏览器在解析文件时,会将html文档转换为document对象,在浏览器环境中运行的脚本文件都可以获取到它,通过操作document对象暴露的接口可以直接操作页面上的DOM节点.但是DOM读写是非常耗性能的,很容易触发不必要的重绘和重排,为了更好地处理DOM操作,Virtual-DOM技术就诞生了.Virtual-DOM就是在javascript中模拟真实DOM的结构,通过数据追踪和状态对比来减少对于真实DOM的操作,以

javascript的执行机制—Event Loop

既然今天要谈的是javascript的事件循环机制,要理解事件循环,首先要知道事件循环是什么. 我们先从一个例子来看一下javascript的执行顺序. <script> setTimeout(function() { console.log('定时器开始了.'); },0) new Promise(function(resolve) { console.log('马上执行for循环了'); for (let i = 0; i < 10000; i++) { i == 99 &&

记一次途家面试中问到的JavaScript事件机制:Event Loop

前几天去途家面试,问到了事件机制,以及异步队列的问题.很遗憾,当时答错了.回来之后查了下资料,看到阮一峰老师博客的分析,感觉讲的非常浅显易懂,就分享过来了. 一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. JavaScript的单线程,与它的用途有关.作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM.这决定了它只能是单线程,

javascript基础修炼(1)——一道十面埋伏的原型链面试题

在基础面前,一切技巧都是浮云. 题目是这样的 要求写出控制台的输出. function Parent() { this.a = 1; this.b = [1, 2, this.a]; this.c = { demo: 5 }; this.show = function () { console.log(this.a , this.b , this.c.demo ); } } function Child() { this.a = 2; this.change = function () { th

javascript基础修炼(6)——前端路由的基本原理

[造轮子]是笔者学习和理解一些较复杂的代码结构时的常用方法,它很慢,但是效果却胜过你读十几篇相关的文章.为已知的API方法自行编写实现,遇到自己无法复现的部分再有针对性地去查资料,最后当你再去学习官方代码的时候,就会明白这样做的价值,总有一天,你也将有能力写出大师级的代码. 一. 前端路由 现代前端开发中最流行的页面模型,莫过于SPA单页应用架构.单页面应用指的是应用只有一个主页面,通过动态替换DOM内容并同步修改url地址,来模拟多页应用的效果,切换页面的功能直接由前台脚本来完成,而不是由后端