Skip to content

Commit

Permalink
perf(core): replace neo-async with a minimal helper (#8282)
Browse files Browse the repository at this point in the history
* perf(core): replace `neo-async` with a minimal helper

* fix: lock
  • Loading branch information
chenjiahan authored Oct 31, 2024
1 parent 79971ff commit b3ee626
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 12 deletions.
2 changes: 0 additions & 2 deletions packages/rspack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,13 @@
"@swc/core": "1.4.0",
"@swc/types": "0.1.12",
"@types/graceful-fs": "4.1.9",
"@types/neo-async": "^2.6.6",
"@types/watchpack": "^2.4.0",
"@types/webpack-sources": "3.2.3",
"browserslist": "^4.21.3",
"cross-env": "^7.0.3",
"enhanced-resolve": "5.12.0",
"graceful-fs": "4.2.10",
"json-parse-even-better-errors": "^3.0.0",
"neo-async": "2.6.2",
"prebundle": "^1.1.0",
"tsc-alias": "^1.8.8",
"tsup": "^8.3.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/rspack/src/MultiCompiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
*/

import * as liteTapable from "@rspack/lite-tapable";
import asyncLib from "neo-async";
import type { Compiler, RspackOptions, Stats } from ".";
import MultiStats from "./MultiStats";
import MultiWatching from "./MultiWatching";
import type { WatchOptions } from "./config";
import ConcurrentCompilationError from "./error/ConcurrentCompilationError";
import ArrayQueue from "./util/ArrayQueue";
import asyncLib from "./util/asyncLib";
import type { InputFileSystem, WatchFileSystem } from "./util/fs";

interface Node<T> {
Expand Down
4 changes: 2 additions & 2 deletions packages/rspack/src/MultiWatching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* https://github.com/webpack/webpack/blob/main/LICENSE
*/

import asyncLib from "neo-async";
import asyncLib from "./util/asyncLib";

import type { Callback } from "@rspack/lite-tapable";
import type { MultiCompiler } from "./MultiCompiler";
Expand Down Expand Up @@ -43,7 +43,7 @@ class MultiWatching {
}

close(callback: Callback<Error, void>) {
asyncLib.forEach(
asyncLib.each(
this.watchings,
(watching, finishedCallback) => {
watching.close(finishedCallback);
Expand Down
2 changes: 1 addition & 1 deletion packages/rspack/src/lib/CacheFacade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* https://github.com/webpack/webpack/blob/main/LICENSE
*/

import asyncLib from "neo-async";
import asyncLib from "../util/asyncLib";
import { getter as getLazyHashedEtag } from "./cache/getLazyHashedEtag.js";
import { mergeEtags } from "./cache/mergeEtags.js";

Expand Down
116 changes: 116 additions & 0 deletions packages/rspack/src/util/asyncLib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* The following code is modified based on
* https://github.com/suguru03/neo-async/blob/master/lib/async.js
*
* MIT Licensed
* Author Suguru Motegi
* Copyright (c) 2014-2018 Suguru Motegi
* https://github.com/suguru03/neo-async/blob/master/LICENSE
*/
export interface Dictionary<T> {
[key: string]: T;
}
export type IterableCollection<T> = T[] | IterableIterator<T> | Dictionary<T>;
export type ErrorCallback<E = Error> = (err?: E | null) => void;
export type AsyncIterator<T, E = Error> = (
item: T,
callback: ErrorCallback<E>
) => void;

function throwError() {
throw new Error("Callback was already called.");
}

function noop() {}

function onlyOnce<E = Error>(func: ErrorCallback<E>): ErrorCallback<E> {
return (err?: E | null) => {
const fn = func;
// biome-ignore lint/style/noParameterAssign:
func = throwError;
fn(err);
};
}

function once<E = Error>(func: ErrorCallback<E>): ErrorCallback<E> {
return (err?: E | null) => {
const fn = func;
// biome-ignore lint/style/noParameterAssign:
func = noop;
fn(err);
};
}

function arrayEach<T, E = Error>(
array: T[],
iterator: (item: T, callback: ErrorCallback<E>) => void,
callback: ErrorCallback<E>
): void {
let index = -1;
while (++index < array.length) {
iterator(array[index], onlyOnce(callback));
}
}

/**
* @example
*
* // array
* var order = [];
* var array = [1, 3, 2];
* var iterator = function(num, done) {
* setTimeout(function() {
* order.push(num);
* done();
* }, num * 10);
* };
* asyncLib.each(array, iterator, function(err, res) {
* console.log(res); // undefined
* console.log(order); // [1, 2, 3]
* });
*
* @example
*
* // break
* var order = [];
* var array = [1, 3, 2];
* var iterator = function(num, done) {
* setTimeout(function() {
* order.push(num);
* done(null, num !== 2);
* }, num * 10);
* };
* asyncLib.each(array, iterator, function(err, res) {
* console.log(res); // undefined
* console.log(order); // [1, 2]
* });
*
*/
function each<T, E = Error>(
collection: IterableCollection<T>,
iterator: AsyncIterator<T, E>,
originalCallback: ErrorCallback<E>
) {
let callback = once(originalCallback);
let size = 0;
let completed = 0;

const done: ErrorCallback<E> = err => {
if (err) {
callback = once(callback);
callback(err);
} else if (++completed === size) {
callback(null);
}
};

if (Array.isArray(collection)) {
size = collection.length;
arrayEach(collection, iterator, done);
}
if (!size) {
callback(null);
}
}

export default { each };
6 changes: 0 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 comments on commit b3ee626

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2024-10-31 02f0c85) Current Change
10000_big_production-mode + exec 49.3 s ± 1.56 s 47.2 s ± 1.1 s -4.29 %
10000_development-mode + exec 2.12 s ± 33 ms 2.09 s ± 24 ms -1.47 %
10000_development-mode_hmr + exec 638 ms ± 4.3 ms 638 ms ± 2.5 ms +0.01 %
10000_production-mode + exec 2.69 s ± 41 ms 2.63 s ± 30 ms -2.39 %
arco-pro_development-mode + exec 1.79 s ± 73 ms 1.76 s ± 83 ms -1.63 %
arco-pro_development-mode_hmr + exec 428 ms ± 1.1 ms 429 ms ± 1.4 ms +0.06 %
arco-pro_production-mode + exec 3.21 s ± 130 ms 3.2 s ± 83 ms -0.31 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.25 s ± 68 ms 3.23 s ± 69 ms -0.73 %
threejs_development-mode_10x + exec 1.62 s ± 20 ms 1.62 s ± 16 ms -0.33 %
threejs_development-mode_10x_hmr + exec 770 ms ± 13 ms 771 ms ± 4.1 ms +0.18 %
threejs_production-mode_10x + exec 5.01 s ± 27 ms 5.01 s ± 37 ms -0.04 %

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ran ecosystem CI: Open

suite result
modernjs ✅ success
_selftest ✅ success
rspress ✅ success
rslib ✅ success
rsbuild ✅ success
examples ✅ success
devserver ✅ success

Please sign in to comment.