目录
一、nodejs架构组成
Node.js是一个构建在Chrome浏览器V8引擎上的JavaScript运行环境,也是我们使用过程中直接能调用的API。http,fs,events是常用模块。
底层库:V8是JavaScript的虚拟机,为JavaScript提供了在非浏览器端运行的环境;
libuv: 为Node.js提供了跨平台,线程池,异步I/O能力;是Node.js高效的主要原因;
C-ares:提供了异步处理DNS相关的能力;
http_parser、OpenSSL、zlib等:提供包括http解析、SSL、数据压缩等能⼒。
Node bindings 是JavaScript与C/C++库之间连接的桥,通过桥,底层实现的C/C++库暴露给JavaScript环境,同时把js传入V8,解析后交给libuv发起非阻塞I/O,并等待事件循环调度。
二、Node.js是高效的
任务调度一般有两种方法:
单线程串执行,执行顺序与编码顺序一致。但无法充分利用多核CPU,当并行极大的时候,单核CPU理论上计算能力是100%。
多线程并行处理。js是单线程语言,但它能调用底层的C/C++库,底层是多线程的,所以可以进行多线程处理。可以有效的利用多核CPU,但创建与切换线程开销大,涉及到锁,状态同步等问题,CPU经常会等待I/O结束,性能被白白消耗。
Node.js为什么是高效的?
除了它是单线程外,必须配合非阻塞I/O。
非阻塞I/O:
发起I/O操作不等得到响应或者超时就立即返回,让进程进行其他操作,但要通过轮询方式不断去check数据是否已准备好。就是发起I/O操作后,就让它去操作,主线程继续往下执行,不时的去问问它干完没。等它干完后再把数据返回结果的处理代码放在回调函数中(等它干完再把干完的结果拿过来用),从而提高了程序的执行效率。
三、事件循环
事件循环有六个阶段:
这个图从右往左看,右边incoming是图的入口。
timers:这个阶段执行定时器队列中的回调,setTimeout() 和 setInterval();
I/O callbacks: 这个阶段执行几乎所有的回调,close事件,定时器和setImmediate()除外;
idle,prepare:这个阶段仅再内部使用,可以不必理会;
poll: 等待新的I/O事件,node在一些特殊的情况下会阻塞这里,V8引擎将js代码解析后传入libuv后,循环首先进入poll阶段,这些事件需要在队列中排队,先进先出;
check: setImmediate() 的回调会在这个阶段执行;
close callbacks: close事件的回调。
所以,在js中执行代码是有先后顺序的,优先级高的先执行
const fs = require('fs')
const axios = require('axios')
console.log("begin")
// end先打印, 里面的回调函数会去排队
//timer
setTimeout(() => {
console.log('setTimeout')
},0)
// Promise.resolve构建了一个成功的Promise实例
//微任务 微任务可以插队,优先执行
Promise.resolve().then(() => {
console.log('promise')
})
// io流操作
//I/O操作
fs.readFile('./a.text',(err,buffer) => {
console.log(buffer)
})
//I/O操作
axios.get('http://47.100.232.228:8888/index/carousel/findAll')
.then(res => {
console.log(res.status)
})
;(function() {
console.log('立即执行函数')
})()
console.log("end")
这是它们执行的先后顺序。
Event Loop有一个或多个宏任务队列,除了微任务所有的任务都叫宏任务。当执行栈为空时,会从任务队列里获取任务,加入到执行栈中。
优先级:
loop -> 微任务
Process.nextTick
Promise
Object.observe
MutationObserver(监听dom树变化)
check -> setImmediate()
close -> callback
timer -> 超时调用,间歇调用
I/O操作
node.js使用express+MySQL:Node.js: express + MySQL的使用_掉头发类型的选手的博客-CSDN博客