初识node.js

90 阅读3分钟

一.初识node.js

根据官网,node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境

二.node.js 结构概览

概览.jpg

三.阻塞vs非阻塞

同步:代码按顺序一行行执行,下一步等待上一步代码执行完成,依赖上一步返回结果

console.log(1);
console.log(2);
// 输出顺序: 1,2

异步:代码下一步不依赖上一步的结果,后面代码先执行

setTimeout(function(){
console.log(1);
},1000)
console.log(2);
// 输出顺序: 2,1

四.异步代码的执行

002.jpg node.js如果是单线程的,那异步代码例如 网络操作,文件操作;是怎么执行的呢?这就涉及到 libuv 了,网络操作,操作系统比较擅长处理这一类事情,优先处理,处理完成之后通知 event loop执行回调函数;而文件操作,libuv 会分配一个线程池,里面有多个线程,每个线程一次处理单个任务;处理完成之后通知 event loop 执行回调函数;线程池的资源是宝贵的,所以会优先让操作系统处理任务

五.event loop是如何运转的?

003.jpg event loop 可以理解为一个循环,自node.js进程运行开始就开始运作了,直到进程退出;主要分为四个阶段(phase),从上至下分为 Timers, IO callbacks,check,close;times阶段 主要用于执行 setTimeout,setInterval 回调队列;IO callbacks阶段主要用于执行 文件,网络,输入输出操作的回调队列;check阶段主要用于执行 setImmediate 回调队列;close 阶段用于执行 文件关闭,或网络关闭的close 事件;

根据node.js官网文档,其实中间还有一个阶段,idle 阶段;主要是内部使用;

六.node.js与php,python等有什么不同?

三者都是单线程模型,php,python处理请求表现是阻塞的,依赖于 Apache 服务器,每个请求进来都会新开一个线程去处理,随着用户数增多,线程数增多,服务器资源也消耗更多;而 node.js 借助 libuv 处理异步请求,表现是非阻塞的,高并发场景下非常适合;node.js作为服务器,非常擅长处理网络请求,以及发送数据,但不擅长cpu重计算场景,会加重cpu负担,导致 event loop 阻塞;

七.其他

发布订阅模式

const EventEmitter = require('events');
const celebrator = new EventEmitter();

celebrator.on('win',()=>{
    console.log('win1')
  })
celebrator.on('win',()=>{
    console.log('win2')
  })
celebrator.emit('win')

process.on('exit',function(code){
    console.log('code',code)
  })

http

// 作为客户端发送请求

// 方法1
const {request} = require('https')

const req = request('https://www.baidu.com',(res)=>{
	res.on('data',(chunk)=>{
		console.log(chunk)
	})
	res.on('end',()=>{
	   console.log('no more data ')
	})
})
req.end()

//方法2
const {get} = require('https')

const req = get('https://www.baidu.com',(res)=>{
	res.on('data',(chunk)=>{
		console.log(chunk)
	})
	res.on('end',()=>{
	   console.log('no more data ')
	})
})

加载Ecmascript模块

node.js 中使用Ecmascript模块,由于node.js 加载模块,模块查找顺序默认会按照加上 .js, .json, .node 后缀寻找;有两种方式可以加载Ecmascript模块,一种方式是将文件后缀改为 .mjs;另一种方式是 package.json中 加上 type:module 属性

模块缓存

模块被加载之后,无论后序被重复加载多少次,被加载模块代码只会执行一次,并存储在内存中;例如

// request.js
module.exports.send=function(){
    console.log('send data')
}
console.log('request module loaded')

// index.js
const request = require('./request')
const request2 = require('./request')

// 输出结果
// request module loaded // 虽然被加载了两次,只会输出一次