ES6/TypeScript 动态导入 - 由于静态导入导致启动时间缓慢 (Nodejs CLI)
ES6/TypeScript Dynamic Imports - Slow launch time because of static imports (Nodejs CLI)
在我的 nodejs 代码中,我用 ES6 import { ... } from "x"
替换了许多 require(x)
。
不幸的是,这对我的 nodejs-CLI-program 的启动时间非常不利。
让我先给大家介绍一下背景:
我有一个使用一大堆外部包的 nodejs-CLI 程序,但这些包中的大多数只在极少数情况下才需要(例如,如果特定标志被传递到我的程序)。
这些导入对我的程序的启动时间造成了很大的开销。
由于这些导入,即使像 myprogram --help
这样的微不足道的命令也需要超过一秒的时间。
为了解决这个启动时间问题,我想对某些功能进行“动态导入”。
换句话说,只有当给定的 CLI 命令实际需要特定功能时,我才想导入某些包。
使用旧的 require
机制,这可以通过有条件地调用 require
来实现。但是,我不确定如何为现代 TypeScript 代码执行此操作。
如果您对此类启动时间问题有任何建议,请告诉我。
您可以在 TypeScript 中使用 Dynamic Import Expressions:
Dynamic import expressions are a new feature and part of ECMAScript
that allows users to asynchronously request a module at any arbitrary
point in your program.
This means that you can conditionally and lazily import other modules
and libraries. For example, here’s an async function that only imports
a utility library when it’s needed.
(在JavaScript中还是提案:https://github.com/tc39/proposal-dynamic-import)
示例:
您有一个主文件和两个依赖项。
./main.ts
./dependency-a.ts
./dependency-b.ts
依赖项 'a' 加载速度很快。
console.log('exporting dependency-a');
export const a = () => {
console.log('called dependency-a');
};
虽然依赖项 'b' 加载缓慢。
console.log('exporting dependency-b');
// We'll emulate a slow synchronous task with a loop to add delay
//
function wait(ms: number) {
var start = Date.now(),
now = start;
while (now - start < ms) {
now = Date.now();
}
}
wait(5000);
export const b = () => {
console.log('called dependency-b');
};
在您的主文件中,您有条件地调用导出函数,但由于依赖性 'b',启动时间会很慢,即使您只想调用依赖性 'a':
import { a } from './dependency-a';
import { b } from './dependency-b';
const run = (dep: 'a' | 'b') => {
switch (dep) {
case 'a':
return a();
case 'b':
return b();
default:
console.log('do nothing');
}
};
run();
您可以像这样使用动态 import() 表达式:
const run = (dep: 'a' | 'b') => {
switch (dep) {
case 'a':
return import('./dependency-a').then(({ a }) => {
a();
});
case 'b':
return import('./dependency-b').then(({ b }) => {
b();
});
default:
console.log('do nothing');
}
};
run('a');
缓慢的依赖项 'b' - 以及它的导入语句,如果有的话 - 将不会在你 运行 依赖项 'a' 时加载。这意味着您的 CLI 将有更好的启动时间。
在我的 nodejs 代码中,我用 ES6 import { ... } from "x"
替换了许多 require(x)
。
不幸的是,这对我的 nodejs-CLI-program 的启动时间非常不利。
让我先给大家介绍一下背景:
我有一个使用一大堆外部包的 nodejs-CLI 程序,但这些包中的大多数只在极少数情况下才需要(例如,如果特定标志被传递到我的程序)。
这些导入对我的程序的启动时间造成了很大的开销。
由于这些导入,即使像 myprogram --help
这样的微不足道的命令也需要超过一秒的时间。
为了解决这个启动时间问题,我想对某些功能进行“动态导入”。 换句话说,只有当给定的 CLI 命令实际需要特定功能时,我才想导入某些包。
使用旧的 require
机制,这可以通过有条件地调用 require
来实现。但是,我不确定如何为现代 TypeScript 代码执行此操作。
如果您对此类启动时间问题有任何建议,请告诉我。
您可以在 TypeScript 中使用 Dynamic Import Expressions:
Dynamic import expressions are a new feature and part of ECMAScript that allows users to asynchronously request a module at any arbitrary point in your program.
This means that you can conditionally and lazily import other modules and libraries. For example, here’s an async function that only imports a utility library when it’s needed.
(在JavaScript中还是提案:https://github.com/tc39/proposal-dynamic-import)
示例:
您有一个主文件和两个依赖项。
./main.ts
./dependency-a.ts
./dependency-b.ts
依赖项 'a' 加载速度很快。
console.log('exporting dependency-a');
export const a = () => {
console.log('called dependency-a');
};
虽然依赖项 'b' 加载缓慢。
console.log('exporting dependency-b');
// We'll emulate a slow synchronous task with a loop to add delay
//
function wait(ms: number) {
var start = Date.now(),
now = start;
while (now - start < ms) {
now = Date.now();
}
}
wait(5000);
export const b = () => {
console.log('called dependency-b');
};
在您的主文件中,您有条件地调用导出函数,但由于依赖性 'b',启动时间会很慢,即使您只想调用依赖性 'a':
import { a } from './dependency-a';
import { b } from './dependency-b';
const run = (dep: 'a' | 'b') => {
switch (dep) {
case 'a':
return a();
case 'b':
return b();
default:
console.log('do nothing');
}
};
run();
您可以像这样使用动态 import() 表达式:
const run = (dep: 'a' | 'b') => {
switch (dep) {
case 'a':
return import('./dependency-a').then(({ a }) => {
a();
});
case 'b':
return import('./dependency-b').then(({ b }) => {
b();
});
default:
console.log('do nothing');
}
};
run('a');
缓慢的依赖项 'b' - 以及它的导入语句,如果有的话 - 将不会在你 运行 依赖项 'a' 时加载。这意味着您的 CLI 将有更好的启动时间。