JavaScript学习 之 Event Loop

目录

Event Loop

什么是Event Loop? 简单来说就是

处理Event的Loop

那么 什么是Loop呢? 简单来说就是

Loop就是一个死循环

死循环多简单 谁都会写

while(1) {
    // 处理event
}

当然 这是不实用的loop

因为 没有event的时候 还总是这么执行死循环 会对资源造成极大的消耗 结果就是设备变慢了�电量消耗了

所以 通常情况下 会对loop加入休眠-唤醒机制

Node.js Event Loop最准确的图示来自官方文档The Node.js Event Loop, Timers, and process.nextTick()

当然 还有一个更好理解但可能不适用于最新Node.js版本的图示@shigeki

但是 我的图应该还是最轻松 + 最好理解的 (为了实现最好理解 下图牺牲了一些准确性)

 -----------> timers
|               |
|               | <--- ① setTimeout()/setInterval()
|               |
|           I/O callbacks
|               |
|               | <--- ③ process.nextTick()
|               |
|        current operation
|               |
|               | <--- ③ process.nextTick()
|               |
|           poll queue
|               |
|               | <--- ③ process.nextTick()
|               | 
|             check 
|               |
|               | <--- ② setImmediate() <--- ③ process.nextTick()
|               | 
 ---------------

从上图我们可以得到以下最直观的认识

process.nextTick() 早于 setImmediate() 早于 setTimeout()/setInterval() 

setTimeout()/setInterval()

setTimeout()/setInterval()应该是很常用也很好理解的: 用法设置一个定时器 延迟定时执行某一任务

两个的区别在于: 前者指定的任务是一次性执行 后者则为反复执行

因此 本文就不赘述了 只是有一点需要读者注意的是 如果想要实现每次页面重绘时执行任务

优先选择requestAnimationFrame接口来替代setTimeout()

setImmediate()/process.nextTick()

比较难理解的应该setImmediate()与process.nextTick() 从上面的介绍来看

两者都可以实现异步 只是执行时间 process.nextTick() 早于 setImmediate()

官方的结论比较简单直接

尽可能使用setImmediate()而不是process.nextTick() 因为 更好定位问题且兼容性浏览器环境

那么process.nextTick()是没有存在的意义了呢? 当然不是 否则这个接口早就被删除了好吧

触发事件

例如 实现一个读取文件的库 在读取文件之前发送start事件 在读取文件后发送data消息 实现代码如下

var fs = require('fs');
var EventEmitter = require('events').EventEmitter;

function StreamLibrary(resourceName) {
    var self = this;

    self.emit('start');

    fs.readFile(resourceName, function (err, data) {
        self.emit('data', data);
    });
}
StreamLibrary.prototype.__proto__ = EventEmitter.prototype; // inherit from EventEmitter

使用这个库的应用程序代码如下

var stream = new StreamLibrary('./demo.txt');
stream.on('start', function () {
    console.log('Reading has started');
});
stream.on('data', function (chunk) {
    console.log('Received: ' + chunk);
});

上述代码中的demo.txt是在代码执行目录添加的测试文件 内容为"demo"

使用babel-node执行该段代码 打印结果如下

Received: demo

关于babel-node的更多介绍请参考JavaScript学习 之 版本

我们发现start事件没有打印 这是因为在start事件emit的时候(StreamLibrary对象创建时) 此时事件的回调函数还没有准备好(stream.on('start', callback))

因此 我们需要使用process.nextTick()来保证事件的时序 修改后的StreamLibrary.js代码如下

function StreamLibrary(resourceName) {
    var self = this;

    process.nextTick(function () {
        self.emit('start');
    });

    fs.readFile(resourceName, function (err, data) {
        self.emit('data', data);
    });
}

再次使用babel-node执行该段代码 打印结果如下

Reading has started
Received: demo

交叉执行

基于JavaScript的Node.js其实并不擅长运算密集型的任务 但是 如果确实有这样的情况 可以采用这面的方式来处理

var http = require('http');

function compute() {
    // performs complicated calculations continuously
    // ...
    process.nextTick(compute);
}

http.createServer(function(req, res) {
     res.writeHead(200, {'Content-Type': 'text/plain'});
     res.end('Hello World');
}).listen(5000, '127.0.0.1');

compute();

这个应用模式就像一个单线程的web server 在这里我们就可以使用process.nextTick()来交叉执行compute()和正常的事件响应

在这个过程中 如果有新的http请求进来 事件循环机制会先处理新的请求 然后再调用compute()

小结

如果只是应用层编码的话 我们主要了解的是setTimeout()/setInterval()以及setImmediate()

如果还要设计库开发的话 我们还需要掌握process.nextTick()的原理和使用

当然 也会有一些面试官�和面试者为了互相"敷衍" 问这样的问题

递归调用process.nextTick()会发生什么?

答案参考这里的eventloop下的nextTick.js

无论问或不问 了解JavaScript和Node.js的Event Loop对于深入理解环境和系统都是有很大帮助的

参考

更多文章, 请支持我的个人博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,647评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,690评论 2 374
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,739评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,692评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,552评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,410评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,819评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,463评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,752评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,789评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,572评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,414评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,833评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,054评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,345评论 1 254
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,810评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,016评论 2 337

推荐阅读更多精彩内容