Skip to content

import('typescript') is 3x slower than require('typescript') #35574

Closed

Description

@AviVahl
  • Version: 14.13.1
  • Platform: Linux. Fedora 32.
  • Subsystem: modules?

What steps will reproduce the bug?

mkdir slow-esm
cd slow-esm
npm init -y
npm i typescript

Now create two files:

a.js:

(async () => {
    const start = Date.now();
    require('typescript')
    console.log(`requiring typescript took ${Date.now() - start}ms`);
})()

a.mjs

(async () => {
    const start = Date.now();
    await import('typescript');
    console.log(`requiring typescript took ${Date.now() - start}ms`)
})()

node a.js outputs:
requiring typescript took 147ms

node a.mjs outputs:
requiring typescript took 440ms

How often does it reproduce? Is there a required condition?

The numbers change +-10ms, but the slowdown is pretty noticable.

What is the expected behavior?

Have a somewhat similar evaluation speed?

What do you see instead?

3x slowdown.

Additional information

I actually converted a commonjs app to native esm... the slowdown was clear, so I decided to make the naive check.

EDIT: Is it because typescript is a commonjs module? tokenization kicks in to find named exports? If so, is there a way to turn it off so I can check the speed without it?

Activity

  1. AviVahl commented on Oct 9, 2020

    @AviVahl
    Author

    Alright, I checked several versions. 14.13.0 has the speed regression. 14.12.0 works properly (~150ms on both files).
    #35249 causing a speed regression is my guess.
    Not sure if this is an acceptable/known tradeoff.

    I'm considering to use commonjs as long as I'm importing other commonjs libraries. Don't want that extra slowdown. :(

  2. AviVahl commented on Oct 9, 2020

    @AviVahl
    Author

    It should be noted that I have a pretty speedy laptop (i7-7700HQ w/ 32GB of RAM) and I could notice the slowdown even before actually measuring. I wonder how it feels on slower machines.

  3. aduh95 commented on Oct 9, 2020

    @aduh95
    Contributor

    @nodejs/modules-active-members

  4. AviVahl commented on Oct 9, 2020

    @AviVahl
    Author

    lodash is also at least 3x slower on my machine (from ~20ms to ~75-90ms).

  5. MylesBorins commented on Oct 10, 2020

    @MylesBorins
    Contributor
  6. added
    esmIssues and PRs related to the ECMAScript Modules implementation.
    on Oct 10, 2020
  7. guybedford commented on Oct 10, 2020

    @guybedford
    Contributor

    Firstly it's worth noting this is only for very large JS files (TypeScript is a single 8.9MB file). Most imports of ESM don't hit this kind of perf.

    The issue here is not actually the performance of the JS parser itself, but the fact that when you run a cold start against TypeScript, the v8 optimizer hasn't yet kicked in so the v8 execution of the parser is running in slow mode for the entire 8.9MB TypeScript file.

    Running a full warmup cycle against TypeScript before I get:

    typescript/lib/typescript.js (8.9MB): 161ms (require)
    typescript/lib/typescript.js (8.9MB): 436ms (esm parse cold)
    typescript/lib/typescript.js (8.9MB): 228ms (esm parse warm)

    Interestingly this points to a workaround - in any large application, import the small dependencies first, then the larger dependencies. This way the parser is warmed up by the time it gets to the larger dependencies.

    This is also where using native / Wasm code would provide a benefit because not only do we get a ~50% speed improvement but the code is then also effectively always "warm".

    We would have used the Wasm implementation by default, but Node.js cannot support Wasm in core when using the new --jitless flag.

  8. AviVahl commented on Oct 10, 2020

    @AviVahl
    Author

    Thanks for looking into it. I'll follow the PR...

  9. MylesBorins commented on Oct 12, 2020

    @MylesBorins
    Contributor

    The WASM update has significantly improved perf:

    v14.12.0

    test CJS
    
    real	0m0.161s
    user	0m0.141s
    sys	0m0.018s
    
    test ESM
    
    real	0m0.164s
    user	0m0.145s
    sys	0m0.019s
    

    v14.13.1

    real	0m0.169s
    user	0m0.150s
    sys	0m0.019s
    
    test ESM
    
    real	0m0.403s
    user	0m0.387s
    sys	0m0.021s
    

    master /w wasm change

    
    test CJS
    
    real	0m0.163s
    user	0m0.142s
    sys	0m0.019s
    
    test ESM
    
    real	0m0.249s
    user	0m0.238s
    sys	0m0.026s
    
  10. MylesBorins commented on Oct 13, 2020

    @MylesBorins
    Contributor

    I'm going to go ahead and close this as the wasm change has landed on master and will go out in the next v14.x release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    esmIssues and PRs related to the ECMAScript Modules implementation.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions