关于nodejs的异步I/O模型!JavaScript事件机制

知识前提:

了解之前,需要掌握一下知识
js引擎执行机制
参考
JS的执行环境是单线程的,(这个线程就是浏览器的JS引擎),一次只能执行做一件事情;
浏览器内核实现了多个线程异步执行,这些线程在内核的控制下相互配合从而保持同步

浏览器的线程:

浏览器的工作原理:

js引擎是事件驱动的,它一直在等待着任务任务队列中的任务到来,又由于js是单线程的,所以很对任务会出现排队的情况

参考这里

虽然JavaScript是单线程执行的,但是浏览器并不是单线程执行的,它们有JavaScript的执行线程、UI节点的渲染线程,图片等资源的加载线程,以及Ajax请求线程等。在Chrome设计中,为了防止因一个Tab window的奔溃而影响整个浏览器,它的每一个Tab被设计为一个进程;在Chrome设计中存在很多的进程,并利用进程间通讯来完成它们之间的同步,因此这也是Chrome快速的法宝之一。对于Ajax的请求也需要特殊线程来执行,当需要发送一个Ajax请求的时候,浏览器会开辟一个新的线程来执行HTTP的请求,它并不会阻塞JavaScript线程的执行,HTTP请求状态变更事件会被作为回调放入到浏览器的事件队列中等待被执行。

nodejs事件循环机制
参考


(全局任务属于宏任务)
1、如果当前任务能够直接执行,那么直接执行
2、如果是宏任务,则放入宏任务队列中
3、如果是微任务,则放入为任务队列中
4、当执行栈为空了之后,执行整个为微任务队列
5、但执行栈又为空了之后,则执行整个宏任务队列

引自这里

虽然JavaScript是单线程执行的,但是浏览器并不是单线程执行的,它们有JavaScript的执行线程、UI节点的渲染线程,图片等资源的加载线程,以及Ajax请求线程等。在Chrome设计中,为了防止因一个Tab window的奔溃而影响整个浏览器,它的每一个Tab被设计为一个进程;在Chrome设计中存在很多的进程,并利用进程间通讯来完成它们之间的同步,因此这也是Chrome快速的法宝之一。对于Ajax的请求也需要特殊线程来执行,当需要发送一个Ajax请求的时候,浏览器会开辟一个新的线程来执行HTTP的请求,它并不会阻塞JavaScript线程的执行,HTTP请求状态变更事件会被作为回调放入到浏览器的事件队列中等待被执行。

函数执行栈

我们的js代码从上到下的执行,当一个函数被执行的时候,都会有一个执行上下文,全局环境也有一个执行上下文,就是全局的上下文。JavaScript将以栈的形式来存储他们。每执行一个函数,就把它上下文存入栈。栈的最底层就是全局上下文,栈顶就是当前正在执行的函数。每当一个函数执行结束,他的执行上下文就从栈中被弹出,释放。最底层的全局上下文,在浏览器关闭的时候才被弹出。

任务队列

macro-task(task):

  • setTimeout/setInterval
  • setImmediate
  • I/O操作
  • UI rendering

micro-task(job):

  • process.nextTick
  • Promise
  • MutationObserve

JavaScript执行的机制是:首先执行调用栈中的函数,当调用栈中的执行上下文全部被弹出,只剩下全局上下文的时候,就开始执行job的执行队列,job的执行完以后就开始执行task的队列中的。先进入的先执行,后进入的后执行。无论是task还是job都是通过函数调用栈来执行。task执行完成一个,js代码会继续检查是否有job需要执行(就像是一个优先级的问题)。就形成了task-job-task-job的循环(其实这里可以将第一次的函数调用栈也看成一个task)。这就形成了event loop.

异步I/O

现在CPU快了,但是IO一般比较慢,是很多操作的瓶颈,很容易组赛,异步能够缓解这种阻塞。
虽然现在的语言/平台基本都能做到异步,但是nodejs历害之处能在一个线程里面异步操作,而其它语言遇到一个请求就需要再开一个线程,在打兵发的时候就很容易吃不消!!!
阻塞I/O:比如你要读一个文件,整个线程都暂停下来,等到文件读完了之后再继续执行。也就是I/O操作阻塞了代码的执行,极大地降低了程序的效率
下面感受一下怎么用Node.js实现非阻塞I/O,以读取文件为例:

var fs = require("fs");
fs.readFile("./testfile", "utf8", function(error, file) {  
     if (error) throw error;  
     console.log("我读完文件了!");
});
console.log("我不会被阻塞!");


代码中给readFile绑定了一个回掉函数,,并且在读完了testfile之后执行回掉函数,期间后面的代码是可以继续执行的。其实node的异步I/O就是这么简单嘿嘿嘿!

 

一只可爱的小前端~~


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章