闽公网安备 35020302035485号
本文介绍了两个 JavaScript 提案:Import Sync 提案和 Defer Import Eval 提案。Import Sync 提案建议引入一个同步导入函数 import.sync,用于在模块已加载的情况下同步导入模块。Defer Import Eval 提案建议引入一种新的同步导入形式 import defer,以避免在应用初始化过程中不必要的 CPU 工作,仅在访问模块属性时触发执行。
.常见使用案例包括获取已加载的模块、条件加载和同步加载模块表达式和声明。
.使用 import defer 导入的模块,其异步依赖会立即执行,而同步部分会被推迟执行。
.通过同步导入和延迟执行,可以提高大型应用程序的性能,避免阻塞主事件循环。
.提供了一个粗略的模块包装器实现示例,用于实现类似 Defer Import Eval 的行为,通过异步加载模块及其依赖项,并在访问属性时同步执行。
// 如果模块可同步获取,则同步导入模块
const ns = import.sync('./mod.js');
当模块不可同步获取或使用顶层 await 时,该函数会抛出一个新错误。模块是否可同步获取则是由主机决定的属性。 import 'app';
// 堆代码 duidaima.com
// 如果 'app' 模块已经加载,则这将始终工作
const app = import.sync('app');
条件加载 let fs;
try {
fs = import.sync('node:fs');
} catch {}
if (fs) {
// 只有当 fs 模块可用时,才使用 node:fs
}
模块表达式和声明的同步加载 // 立即日志输出 'hello world'
import.sync(module {
console.log('hello world');
})
同样适用于模块声明:
module dep {
console.log('hi');
}
module x {
import dep;
}
// 如果两个模块都是同步可用的,日志输出 'hi'
const instance = import.sync(x);
Defer Import Eval 提案(Stage 2.7)// 优化前
const operation = require('operation');
exports.doSomething = function (target) {
return operation(target);
}
// 优化后
exports.doSomething = function (target) {
const operation = require('operation');
return operation(target);
}
对于 ES 模块,可以通过动态导入来实现懒加载:export async function doSomething (target) {
const { operation } = await import('operations');
return operation(target);
}
然而,上面方法并没有解决性能瓶颈问题,尤其是初始化时的 CPU 占用。动态导入常需预加载步骤,并迫使所有函数及其调用者进入异步模型,这与程序的真实意图是不符合的,而且会导致 API 的更改。本提案建议引入一个新的同步导入形式,通过该形式可避免在应用初始化过程中不必要的 CPU 工作,且无需改变模块 API 消费者的使用方式。当访问模块的属性时,仅在必要时触发同步评估。// 示例语法 import defer * as yNamespace from "y";这种导入方式会参与深层图加载,将模块及其依赖项加载至准备执行的状态,但不会立刻执行,只有在访问其属性时才触发执行。
const operation = import.defer('./operation');
function executeOperation(target) {
return operation.default(target);
}
我们还可以用它来实现同步检查模块或内置模块是否可用:let fs;
try {
fs = import.defer('node:fs');
} catch {}
if (fs) {
// 使用 node:fs,仅在其可用时
}
同步属性访问必须同步进行,因此不可能将使用顶级 await 的模块推迟执行。使用 import defer 语法导入的模块,其异步依赖和传递依赖将会被立即执行,而只有同步部分会被推迟。可能大家会有个问题,为什么需优化执行?加载不是瓶颈吗?// LazyModuleLoader.js
async function loadModuleAndDependencies(name) {
const loadedModule = await import.load(`./${name}.js`); // 加载模块,需等待异步完成
const parsedModule = loadedModule.parse();
await Promise.all(parsedModule.imports.map(loadModuleAndDependencies)); // 加载所有依赖
return parsedModule;
}
async function executeAsyncSubgraphs(module) {
if (module.hasTLA) return module.evaluate();
return Promise.all(module.importedModules.map(executeAsyncSubgraphs));
}
export default async function lazyModule(object, name) {
const module = await loadModuleAndDependencies(name);
await executeAsyncSubgraphs(module);
Object.defineProperty(object, name, {
get: function() {
delete object[name];
const value = module.evaluateSync();
Object.defineProperty(object, name, {
value,
writable: true,
configurable: true,
enumerable: true,
});
return value;
},
configurable: true,
enumerable: true,
});
return object;
}
最后