博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript基础修炼(5)—Event Loop(Node.js)
阅读量:5987 次
发布时间:2019-06-20

本文共 2119 字,大约阅读时间需要 7 分钟。

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

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的原理

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

【极力推荐文章】

并不是笔者偷懒不想写这一节,而是在读过了这篇教程以后,自认为除非是剖析更底层的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)

题目分析:

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

将代码块放入事件循环:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

分析:

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

分析:

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

分析:

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/刷新率)就可以了。

编辑/寻水的鱼

本文首发于华为云社区:

转载于:https://www.cnblogs.com/dashnowords/p/9649829.html

你可能感兴趣的文章
c++11初始化列表
查看>>
VC编译器简介(转载)
查看>>
解决thinkphp5验证码在CentOS7上面无法显示的问题
查看>>
Linux下安装MySQL 5.7
查看>>
【转】[C/C++]函数参数的入栈顺序
查看>>
MD5算法
查看>>
AEAI DP开发平台升级说明
查看>>
linux查看主板型号及内存硬件信息
查看>>
从mongo数据库中导出数据的方法
查看>>
.net面试题系列文章八(附答案)
查看>>
关于数据库表字段冗余
查看>>
UIVIew相关知识
查看>>
配置 Exchange 接收多个域的邮件的方法
查看>>
最大公约数
查看>>
Shell 备忘录【1】
查看>>
判断是否是手机浏览器
查看>>
今天下午去了趟中山孙文西路。。。
查看>>
Spring MVC 教程,快速入门,深入分析
查看>>
spring mvc使用fastjson视图解析器报错'Content-Type' cannot contain wildcard type '*'
查看>>
PAT 1043 Is It a Binary Search Tree
查看>>