Skip to content

Commit 1bbf8d0

Browse files
committed
lib: speed up require(), phase 2
Replace calls to fs.readFileSync() with an internal variant that does not create Error objects on failure and is a bit speedier in general. A secondary benefit is that it improves start-up times in the debugger because it no longer emits thousands of exception debug events. On a medium-sized application[0], this commit and its predecessor reduce start-up times from about 1.5s to 0.5s and reduce the number of start-up exceptions from ~6100 to 32, half of them internal to the application. [0] https://github.com/strongloop/loopback-sample-app PR-URL: #1801 Reviewed-By: Trevor Norris <[email protected]>
1 parent b14fd1a commit 1bbf8d0

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

lib/module.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const runInThisContext = require('vm').runInThisContext;
66
const assert = require('assert').ok;
77
const fs = require('fs');
88
const path = require('path');
9+
const internalModuleReadFile = process.binding('fs').internalModuleReadFile;
910
const internalModuleStat = process.binding('fs').internalModuleStat;
1011

1112

@@ -65,10 +66,10 @@ function readPackage(requestPath) {
6566
return packageMainCache[requestPath];
6667
}
6768

68-
try {
69-
var jsonPath = path.resolve(requestPath, 'package.json');
70-
var json = fs.readFileSync(jsonPath, 'utf8');
71-
} catch (e) {
69+
var jsonPath = path.resolve(requestPath, 'package.json');
70+
var json = internalModuleReadFile(jsonPath);
71+
72+
if (json === undefined) {
7273
return false;
7374
}
7475

src/node_file.cc

+47
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
# include <io.h>
2323
#endif
2424

25+
#include <vector>
26+
2527
namespace node {
2628

2729
using v8::Array;
@@ -433,6 +435,50 @@ Local<Value> BuildStatsObject(Environment* env, const uv_stat_t* s) {
433435
return handle_scope.Escape(stats);
434436
}
435437

438+
// Used to speed up module loading. Returns the contents of the file as
439+
// a string or undefined when the file cannot be opened. The speedup
440+
// comes from not creating Error objects on failure.
441+
static void InternalModuleReadFile(const FunctionCallbackInfo<Value>& args) {
442+
Environment* env = Environment::GetCurrent(args);
443+
444+
CHECK(args[0]->IsString());
445+
node::Utf8Value path(env->isolate(), args[0]);
446+
447+
FILE* const stream = fopen(*path, "rb");
448+
if (stream == nullptr) {
449+
return;
450+
}
451+
452+
std::vector<char> chars;
453+
while (!ferror(stream)) {
454+
const size_t kBlockSize = 32 << 10;
455+
const size_t start = chars.size();
456+
chars.resize(start + kBlockSize);
457+
const size_t numchars = fread(&chars[start], 1, kBlockSize, stream);
458+
if (numchars < kBlockSize) {
459+
chars.resize(start + numchars);
460+
}
461+
if (numchars == 0) {
462+
break;
463+
}
464+
}
465+
466+
CHECK_EQ(false, ferror(stream));
467+
CHECK_EQ(0, fclose(stream));
468+
469+
size_t start = 0;
470+
if (chars.size() >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
471+
start = 3; // Skip UTF-8 BOM.
472+
}
473+
474+
Local<String> chars_string =
475+
String::NewFromUtf8(env->isolate(),
476+
&chars[start],
477+
String::kNormalString,
478+
chars.size() - start);
479+
args.GetReturnValue().Set(chars_string);
480+
}
481+
436482
// Used to speed up module loading. Returns 0 if the path refers to
437483
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
438484
// The speedup comes from not creating thousands of Stat and Error objects.
@@ -1161,6 +1207,7 @@ void InitFs(Handle<Object> target,
11611207
env->SetMethod(target, "rmdir", RMDir);
11621208
env->SetMethod(target, "mkdir", MKDir);
11631209
env->SetMethod(target, "readdir", ReadDir);
1210+
env->SetMethod(target, "internalModuleReadFile", InternalModuleReadFile);
11641211
env->SetMethod(target, "internalModuleStat", InternalModuleStat);
11651212
env->SetMethod(target, "stat", Stat);
11661213
env->SetMethod(target, "lstat", LStat);

0 commit comments

Comments
 (0)