Skip to main content

[小题目] nodejs

浏览器和 nodejs 的事件循环有什么区别?​

JS 是单线程的(无论在浏览器还是 nodejs)

浏览器中 JS 执行和 DOM 渲染共用一个线程

异步是单线程解决方案

宏任务和微任务​

宏任务: setTimeout setInterval 网络请求

微任务: 如 promise async/await MutationObserver

微任务在下一轮 DOM 渲染之前执行, 宏任务在之后执行. 所以微任务某种程度上说要比宏任务要快

代码演示:

console.log("start");
setTimeout(() => {
console.log("timeout");
});
Promise.resolve().then(() => {
console.log("promise then");
});
console.log("end");

// start end promisethen timeout
const p = document.createElement("p");
p.innerHTML = "new paragraph";
document.body.appendChild(p);
const list = document.getElementsByTagName("p");
console.log("length", list.length);

console.log("start");
setTimeout(() => {
const list = document.getElementsByTagName("p");
console.log("length on timeout--", list.length);
alert("阻塞 timeout");
});
Promise.resolve().then(() => {
const list = document.getElementsByTagName("p");
console.log("length on promise.then--", list.length);
alert("阻塞 promise");
});
console.log("end");

浏览器 Event Loop 执行过程​

eventloop

上图 左侧 JS 框里的同步代码先执行, 一旦遇到一些比如像 ajax, settimeout 这种异步会通过 web api 的能力把这些异步任务放在 callback queue 里, 等到同步代码执行完再通过 event loop 机制把这些异步函数拿出来放到 stack 里执行.

同时 callback queue 队列又分微任务队列和宏任务队列, 先进先出队列

nodejs 异步​

Nodejs 同样使用 ES 语法, 也是单线程, 也需要异步

异步任务也分: 宏任务 + 微任务

但是, 它的宏任务和微任务, 分不同类型, 有不同优先级

console.log("start");
setImmediate(() => {
console.log("setImmediate");
});
setTimeout(() => {
console.log("setTimeout");
});
Promise.resolve().then(() => {
console.log("promise then");
});
process.nextTick(() => {
console.log("nextTick");
});
console.log("end");

// start
// end
// nextTick
// promise then
// setTimeout
// setImmediate

nodejs 宏任务类型和优先级​

  • Timers: setTimeout setInterval

  • I/O callbacks: 处理网络, 流, TCP 的错误回调

  • Idle, prepare: 闲置状态(nodejs 内部使用)

  • Poll 轮询: 执行 poll 中的 I/O 队列

  • Check 检查: 存储 setImmediate 回调

  • Close callbacks: 关闭回调, 如 socket.on('close')

nodejs 微任务类型和优先级​

包括: process.nextTick, promise, async/await

注意: process.nextTick 优先级最高

nodejs event loop 执行过程​

执行同步代码

执行微任务(process.nextTick 优先级最高)

按顺序执行 6 个类型的宏任务 (每个下一个宏任务开始前都执行当前的微任务)

n

注意事项​

  • 推荐使用 setImmediate 代替 process.nextTick

  • nodejs 高低版本有差异

nodejs 如何开启进程, 进程如何通讯?​

进程: process, OS(操作系统)进行资源分配和调度的最小单位, 有独立内存空间

线程: thread, OS 进行运算调度的最小单位, 共享进程内存空间

JS 是单线程的(在进程中只有 1 个线程进行计算, 如果出现更多线程是其他工具帮助的), 但可以开启多进程执行, 如 WebWorker. Java 是多线程的, 提供了很多 api 帮助开启线程和进程

为何需要多进程?​

多核 cpu, 适合处理多进程. 内存大, 多个进程才能更好利用(单进程有内存上限)

nodejs 如何开启进程 cluster fork​

获取当前进程 id

// 获取当前进程id
console.info(process.pid);
// 目前nodejs没有和thread相关的api, 所以没有办法开启多线程

浏览器中通过 webworker 可以开启另一个进程

nodejs 可以通过 fork 或者 cluster 开启多个进程

开启子进程 child_process.fork 和 cluster.fork, 使用 send 和 on 传递消息

进程是资源调度单位, 是分配内存的. 线程是计算单位, 用于计算的