node基本概念
- Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 (runtime)
- 两个特点:事件驱动 非阻塞 I/O(I/O 可以理解为是文件读写)
- node主线程还是单线程,文件读写内部还是基于多线程
- node应用场景 处理i/o密集型(文件读写),不适合处理cpu密集型(压缩加密 和计算相关的)
- 具体应用
- 服务端渲染vue react
- 中间层 解决跨域问题
- 前端会用node来实现很多工具
- 也可用作后端
node中的this
当用 node 执行一个文件,会把这个文件当成一个模块,这里面的 this console.log(this) // {} 默认把 this 给修改了
前端中访问变量是通过 window 属性,但是后端想访问全局需要通过 global,只有在自执行函数中 this 指向 global
console.log(this, 111); // {}
(function () {
console.log(this, 222); // global
})();
node 中通过 global 可以访问到的属性
- clearInterval clearTimeout...
- queueMicrotask 微任务 基于 promise 实现的
- clearImmediate setImmediate 自己实现的 ie 下也有这两个方法
- node 新增的全局属性
- Buffer node 中的二进制对象(最早的时候浏览器不能直接读写文件)服务端开发要把文件读成二进制的,数据不能存成字符串---采用 Buffer,解决了文件读写的问题
- dirname filename
- process
- setImmediate
以下五个参数可以直接在文件中使用,不能通过global来获取
- 是函数的参数
- __filename,__dirname,exports, module, require
__filename: 代表文件所在路径(绝对路径,固定的)
__dirname: 代表文件所在目录(绝对路径,固定的)
process
process.platform平台 => win32 / darwin(mac 输出),可以根据不同的平台执行不同的命令process.chdir("../")更改目录 但一般不会这样用process.cwd当前工作目录(current working directory)- node 在哪运行就是哪
获取执行命令时的路径,webpack查找配置文件,就是在当前执行命令的路径下查找
process.env- 执行代码时传入环境
- 设置环境变量: 默认就是设置成字符串
window: set A=1 mac: export A=1
process.argv- 执行代码时传入的参数
console.log(process.argv); // 默认有两个 [执行node所在的exe文件, 当前执行的文件]- node 1.js --port 3000 --info abc 执行文件时 这样传参,会以空格分隔放到 argv 当中
console.log(process.argv); // [执行node所在的exe文件, 当前执行的文件,'--port', '3000', '--info', 'abc'] - 解析参数 库:commander/args 命令行管家
process.argv.slice(2).reduce((memo, current, index, arr) => {
if (current.startWith('--')) {
memo[current.slice(2)] = arr[index + 1];
}
return memo;
}, {});
process.nextTick- node 中自己实现的 不属于 node 中的 EventLoop
- 是异步,优先级比 promise 更高
- 当前执行栈的底部,在执行完同步代码之后立即执行
Promise.resolve().then(() => {
console.log('promise');
});
process.nextTick(() => {
console.log('nextTick');
});
// 输出 nextTick / promise
node中的事件环
- node中自己实现了一个事件环机制
- 新版本的node执行结果和浏览器执行的结果是一致的,底层实现的方式不太一样
- 对于浏览器宏任务只有一个队列,对于node创造了多个宏任务队列
- timers: 定时器(setTimeout,setInterval)回调会放到 timers 当中 ✅
- pending callbacks: 执行延迟到下一个循环迭代的 I/O 回调 -- 不关心
- idle,prepare:仅系统内部使用 -- 不关心
- poll: 放 I/O 的回调 ✅
- check: 专门放 setImmediate 回调 ✅
- close callbacks: 一些关闭的回调
- 执行js代码 => nextTixk => 微任务队列 => 宏任务
- 如果在i/o操作中下一个事件队列要执行的是check,所以setsetImmediate优先级高于setTimeout
// 当前默认执行主栈代码 主栈执行完成执行定时器 但是定时器可能没有到达时间
setTimeout(() => {
console.log('setTimeout');
}, 0);
setImmediate(() => {
console.log('setImmediate');
});
// 这两个的输出顺序不固定, 两种情况都有可能
// 但是如果是放在文件读取callback里 就不一样
fs.readFile('./a.txt', 'utf8', (err, data) => {
setTimeout(() => {
console.log('setTimeout');
}, 0);
setImmediate(() => {
console.log('setImmediate');
});
}); // 输出:setImmediate / setTimeout
// 当代码执行完之后 回到poll阶段
// 会在poll阶段卡住
// 检测poll队列是不是空的,不为空会把poll中回调全部执行完毕
// poll为空会去检测有没有setImmediate,有就全部执行
// 没有setImmediate,poll就等着,等着定时器到时间
// 定时器有到时间的,就到timers,执行定时器回调,等待时间到达时可能出现新的callback, 此时也在当前阶段清空
小结: node和浏览器事件环差异--浏览器一个队列,node多个队列。执行顺序都是: 先执行代码 => (node会清空nextTick)=> 清空微任务 => 取出一个宏任务来执行。当到达poll阶段后,如果check阶段为空,而且poll里面也没有io操作,此时不会继续轮训,会等待定时器到达时间重新执行 / 或者有新的i/o操作进入到poll中
node中的模块
- node中常用模块分为三种:
- 内置模块/核心模块 不需要安装直接可以使用 node自带的
- 文件模块 自己写的模块文件 引用的时候使用相对路径或者绝对路径
- 第三方模块 下载后使用 使用方式和内置模块一样
- require就是一个读取文件的操作
- 常用api简介
fs.existsSync(./a.txt)判断文件是否存在fs.readFileSync("./a.txt", "utf8")同步读取文件内容path.join("a", "//b", "c", "..")处理路径拼接 相对路径path.resolve("a", "//b", "c", "..")也具备拼接功能,但是最终出来的结果是一个绝对路径,拼接过程中当遇到/表示的是根路径,默认以当前路径当前路径指的是 process.cwd()解析成绝对路径path.basename("a.js", ".js")// 用路径做减法path.extname("a.js")// .js取后缀名path.relative('a/b/c', '')获取相对路径path.dirname(__filename)=== __dirname- let vm = require("vm"); 可以让字符串执行。
vm.runInNewContext('console.log(a)')沙箱执行 实现一个全新的上下文