Browse Source

Truly synchronous require()

This is to reduce our dependency on wait(). For some reason this patch
affects the timer test:

  % ./node test/mjsunit/test-timers.js
  diff: 989
  diff: 989
  diff: 1989
  diff: 2989

Previously it showed:

  % ./node test/mjsunit/test-timers.js
  diff: 1000
  diff: 1000
  diff: 2000
  diff: 3000

I'm not sure what caused this change, and it's rather disturbing. However I
want to remove wait() as soon as possible and so am pushing this patch
through.

The module loading code is becoming increasingly ugly - this patch has not
helped. A refactor needs to be done soon.
v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
860d008d54
  1. 161
      src/node.js
  2. 10
      test/mjsunit/test-remote-module-loading.js

161
src/node.js

@ -857,6 +857,16 @@ var pathModule = createInternalModule("path", function (exports) {
var path = pathModule.exports;
function existsSync (path) {
try {
fs.statSync(path);
return true;
} catch (e) {
return false;
}
}
process.paths = [ path.join(process.installPrefix, "lib/node/libraries")
];
@ -870,11 +880,16 @@ if (process.env["NODE_PATH"]) {
}
/* Sync unless callback given */
function findModulePath (id, dirs, callback) {
process.assert(dirs.constructor == Array);
if (/^https?:\/\//.exec(id)) {
if (callback) {
callback(id);
} else {
throw new Error("Sync http require not allowed.");
}
return;
}
@ -883,8 +898,11 @@ function findModulePath (id, dirs, callback) {
}
if (dirs.length == 0) {
if (callback) {
callback();
return;
} else {
return; // sync returns null
}
}
var dir = dirs[0];
@ -902,26 +920,37 @@ function findModulePath (id, dirs, callback) {
path.join(dir, id, "index.addon")
];
var searchLocations = function() {
function searchLocations () {
var location = locations.shift();
if (location === undefined) {
findModulePath(id, rest, callback);
return;
if (!location) {
return findModulePath(id, rest, callback);
}
// if async
if (callback) {
path.exists(location, function (found) {
if (found) {
callback(location);
return;
} else {
return searchLocations();
}
searchLocations();
});
};
searchLocations();
})
// if sync
} else {
if (existsSync(location)) {
return location;
} else {
return searchLocations();
}
}
}
return searchLocations();
}
function resolveModulePath(request, parent) {
// sync - no i/o performed
function resolveModulePath(request, parent) {
var id, paths;
if (request.charAt(0) == "." && (request.charAt(1) == "/" || request.charAt(1) == ".")) {
// Relative request
@ -939,6 +968,33 @@ function resolveModulePath(request, parent) {
return [id, paths];
}
function loadModuleSync (request, parent) {
var resolvedModule = resolveModulePath(request, parent);
var id = resolvedModule[0];
var paths = resolvedModule[1];
debug("loadModuleSync REQUEST " + (request) + " parent: " + parent.id);
var cachedModule = internalModuleCache[id] || parent.moduleCache[id];
if (cachedModule) {
debug("found " + JSON.stringify(id) + " in cache");
return cachedModule.exports;
} else {
debug("looking for " + JSON.stringify(id) + " in " + JSON.stringify(paths));
var filename = findModulePath(request, paths);
if (!filename) {
throw new Error("Cannot find module '" + request + "'");
} else {
var module = new Module(id, parent);
module.loadSync(filename);
return module.exports;
}
}
}
function loadModule (request, parent) {
var
// The promise returned from require.async()
@ -947,7 +1003,7 @@ function loadModule (request, parent) {
id = resolvedModule[0],
paths = resolvedModule[1];
// debug("loadModule REQUEST " + (request) + " parent: " + JSON.stringify(parent));
debug("loadModule REQUEST " + (request) + " parent: " + parent.id);
var cachedModule = internalModuleCache[id] || parent.moduleCache[id];
if (cachedModule) {
@ -971,6 +1027,21 @@ function loadModule (request, parent) {
return loadPromise;
};
Module.prototype.loadSync = function (filename) {
debug("loadSync " + JSON.stringify(filename) + " for module " + JSON.stringify(this.id));
process.assert(!this.loaded);
this.filename = filename;
if (filename.match(/\.node$/)) {
this._loadObjectSync(filename);
} else {
this._loadScriptSync(filename);
}
};
Module.prototype.load = function (filename, loadPromise) {
debug("load " + JSON.stringify(filename) + " for module " + JSON.stringify(this.id));
@ -981,13 +1052,20 @@ Module.prototype.load = function (filename, loadPromise) {
this.filename = filename;
if (filename.match(/\.node$/)) {
this.loadObject(filename, loadPromise);
this._loadObject(filename, loadPromise);
} else {
this.loadScript(filename, loadPromise);
this._loadScript(filename, loadPromise);
}
};
Module.prototype.loadObject = function (filename, loadPromise) {
Module.prototype._loadObjectSync = function (filename) {
this.loaded = true;
process.dlopen(filename, this.exports);
};
Module.prototype._loadObject = function (filename, loadPromise) {
var self = this;
// XXX Not yet supporting loading from HTTP. would need to download the
// file, store it to tmp then run dlopen on it.
@ -998,11 +1076,10 @@ Module.prototype.loadObject = function (filename, loadPromise) {
});
};
function cat (id, loadPromise) {
var promise;
debug(id);
if (id.match(/^http:\/\//)) {
promise = new events.Promise();
loadModule('http', process.mainModule)
@ -1025,15 +1102,9 @@ function cat (id, loadPromise) {
return promise;
}
Module.prototype.loadScript = function (filename, loadPromise) {
var self = this;
var catPromise = cat(filename, loadPromise);
catPromise.addErrback(function () {
loadPromise.emitError(new Error("Cannot read " + filename));
});
catPromise.addCallback(function (content) {
Module.prototype._loadContent = function (content, filename) {
var self = this;
// remove shebang
content = content.replace(/^\#\!.*/, '');
@ -1041,8 +1112,8 @@ Module.prototype.loadScript = function (filename, loadPromise) {
return loadModule(url, self); // new child
}
function require (url) {
return requireAsync(url).wait();
function require (path) {
return loadModuleSync(path, self);
}
require.paths = process.paths;
@ -1057,18 +1128,48 @@ Module.prototype.loadScript = function (filename, loadPromise) {
var compiledWrapper = process.compile(wrapper, filename);
compiledWrapper.apply(self.exports, [self.exports, require, self, filename, path.dirname(filename)]);
} catch (e) {
return e;
}
};
Module.prototype._loadScriptSync = function (filename) {
var content = fs.readFileSync(filename);
// remove shebang
content = content.replace(/^\#\!.*/, '');
var e = this._loadContent(content, filename);
if (e) {
throw e;
} else {
this.loaded = true;
}
};
Module.prototype._loadScript = function (filename, loadPromise) {
var self = this;
var catPromise = cat(filename, loadPromise);
catPromise.addErrback(function () {
loadPromise.emitError(new Error("Cannot read " + filename));
});
catPromise.addCallback(function (content) {
var e = self._loadContent(content, filename);
if (e) {
loadPromise.emitError(e);
return;
}
self.waitChildrenLoad(function () {
self._waitChildrenLoad(function () {
self.loaded = true;
loadPromise.emitSuccess(self.exports);
});
});
};
Module.prototype.waitChildrenLoad = function (callback) {
Module.prototype._waitChildrenLoad = function (callback) {
var nloaded = 0;
var children = this.children;
for (var i = 0; i < children.length; i++) {

10
test/mjsunit/test-remote-module-loading.js

@ -17,9 +17,11 @@ var server = http.createServer(function(req, res) {
});
server.listen(PORT);
var httpModule = require('http://localhost:'+PORT+'/moduleA.js');
assert.equal('/moduleA.js', httpModule.httpPath());
modulesLoaded++;
assert.throws(function () {
var httpModule = require('http://localhost:'+PORT+'/moduleA.js');
assert.equal('/moduleA.js', httpModule.httpPath());
modulesLoaded++;
});
var nodeBinary = process.ARGV[0];
var cmd = 'NODE_PATH='+libDir+' '+nodeBinary+' http://localhost:'+PORT+'/moduleB.js';
@ -35,5 +37,5 @@ sys
});
process.addListener('exit', function() {
assert.equal(2, modulesLoaded);
assert.equal(1, modulesLoaded);
});

Loading…
Cancel
Save