首页  >  文章  >  web前端  >  mjs 与 cjs 与事件循环

mjs 与 cjs 与事件循环

WBOY
WBOY原创
2024-09-04 16:39:32999浏览

介绍

开发者大家好!

今天,我们将讨论 Node.js 中 .mjs(ECMAScript 模块)和 .cjs(CommonJS 模块)之间的区别。虽然像 React、Next.js 和 Vue 这样的现代框架通常会自动处理模块支持,但在直接使用 Node.js 时理解这些差异至关重要,尤其是在事件循环和执行顺序方面。

我这次讨论的主要目标是事件循环,在接下来的部分中,我们将看到一些案例。

基本信息

mjs(ECMAScript 模块)支持,

import fs from 'fs'
import https from 'https'

cjs(CommonJS 模块)支持

const fs = require('fs')
const https = require('https')

事件循环和执行顺序

Node.js 事件循环处理具有特定角色和优先级的不同队列。影响执行顺序的两个重要函数是 process.nextTick() 和 setImmediate(),我们时常使用这些函数。

process.nextTick 与 setImmediate

如果您知道 process.nextTick 与 setImmediate 之间的区别那就太好了,如果不知道的话,这是一个非常基本的想法

process.nextTick 确保一段代码在当前函数之后但在任何异步 I/O 操作之前运行。

setImmediate 安排回调函数在任何 I/O 事件之后在事件循环的下一次迭代中执行。

当前代码 -> process.nextTick ->任何 I/O 操作 ->立即设置

代码示例

让我们看一下演示执行顺序的代码片段:

//In case of mjs
import https from "https";
import fs from "fs";

//In case of cjs
const https = require("https");
const fs = require("fs");

setImmediate(() => {
    console.log("setImmediate callback");
});

process.nextTick(() => {
    console.log("nextTick callback");
});

fs.readFile("./async.cjs", (err, data) => {
    console.log("file IO Callback");
});

fs.readdir(process.cwd(), () => console.log("file IO Callback 2"));

https.get("https://www.google.com", (res) => {
    console.log("https callback");
});

setImmediate(() => {
    console.log("setImmediate callback 2");
});

Promise.resolve().then(() => {
    console.log("Promise Callback");
});

process.nextTick(() => {
    console.log("Process nextTick console");
    process.nextTick(() => {
        console.log("Process nextTick console 2");
        process.nextTick(() => {
            console.log("Process nextTick console 3");
            process.nextTick(() => {
                console.log("Process nextTick console 4");
            });
        });
    });
});

Promise.resolve().then(() => {
    console.log("Promise Callback 2");
});

console.log("Main thread mjs");

Promise.resolve().then(() => {
    console.log("Promise Callback 3");
});

预期执行顺序与实际执行顺序

代码应该以这种方式运行和执行

  • 主线
  • 承诺回调
  • nextTick 回调
  • 设置立即回调
  • I/O 回调和输出应该是
Main thread mjs
Promise Callback
Promise Callback 2
Promise Callback 3
nextTick callback
Process nextTick console
Process nextTick console 2
Process nextTick console 3
Process nextTick console 4
setImmediate callback
setImmediate callback 2
file IO Callback
file IO Callback 2
https callback

但是mjs也是这样吗?
不是真的!

这是 mjs 和 cjs 的输出

mjs vs cjs with Event Loop

与 process.nextTick 和 setImmediate 类似,我们也可以在 Promises 中看到相同的行为。

原因是什么?

显然,我们在 mjs(ECMAScript 模块)和 cjs(CommonJS 模块)文件中观察到的有关 setImmediate 和 process.nextTick 的行为差异是由于 Node.js 在不同模块系统中处理事件循环和微任务的方式造成的.

对于 ESM (.mjs):

  • 在 ESM 中,Node.js 使用不同的方法来处理主模块执行。
  • 主模块代码包装在异步函数中,然后执行。
  • 这会导致在处理所有微任务(包括 process.nextTick 和 Promises)后,为事件循环的下一次迭代安排 setImmediate 回调。

对于 CommonJS (.cjs):

  • 在CommonJS中,主模块代码是同步执行的。
  • 这意味着 setImmediate 回调会立即安排,并且可以在某些微任务之前运行(如果它们排队得足够早)。

框架行为

我已经在 Express 和 Nextjs 应用程序(开发模式)中测试了此行为,有趣的是,Express 的行为类似于 cjs,而 Nextjs 的行为类似于 mjs。第一组日志来自 Express,下一组日志来自 Nextjs

mjs vs cjs with Event Loop

结论

直接使用 Node.js 时,了解 .mjs 和 .cjs 文件之间执行顺序的差异至关重要。我希望,这将帮助您更好地理解这些函数与文件的区别和执行。因此,下次当您在应用程序中玩或尝试这些功能时,请记住以下几点:)

再举个例子,ES模块和CommonJS文件执行的区别请参考Node.js官方文档。

以上是mjs 与 cjs 与事件循环的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn