根據上篇自己編譯好的node.exe運行測試實例
當然最簡單的就是helloworld
將該代碼
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
保存爲hello.js
運行node.exe hello.js
D:\pbase>node.exe hello.js
Server running at http://127.0.0.1:1337/
瀏覽器訪問http://localhost:1337返回
hello world.
遺憾的是:上述的node.exe是直接從nodejs.org上下載的,自己編譯的node.exe運行是出錯如下:
huareal@gpx /cygdrive/d/pbase/node-v0.10.16/Debug
# ./node.exe hello.js
node.js:853
throw new Error('No such native module ' + id);
^
Error: No such native module events
at Function.NativeModule.require (node.js:853:13)
at startup (node.js:31:37)
at node.js:901:3
應該是node.js腳本在執行到行853報錯了
第一:
function startup() {
.....
if (!NativeModule.exists(id)) {
throw new Error('No such native module ' + id); //出錯行
}
//錯誤的入口在startup方法
startup();
實現看看Node.js裏面有什麼
一個匿名函數,傳入參數process[線程]
(function(process) {
this.global = this;
function startup() {}
var EventEmitter = NativeModule.require('events').EventEmitter;//通過NativeModule獲取events的事件發射器
process.__proto__ = Object.create(EventEmitter.prototype, { //創建process的__proto__
constructor: {
value: process.constructor
}
});
EventEmitter.call(process);//事件發射器調用process來處理
//接下來的startup的處理
startup.processFatal();
startup.globalVariables();
startup.globalTimeouts();
startup.globalConsole();
startup.processAssert();
startup.processConfig();
startup.processNextTick();
startup.processStdio();
startup.processKillAndExit();
startup.processSignalHandlers();
startup.processChannel();
startup.resolveArgv0();
關注如下的方法
startup.processSignalHandlers = function() {
var addListener = process.addListener;
var removeListener = process.removeListener;
process.on = process.addListener = function(type, listener) {
if (isSignal(type) &&
!signalWraps.hasOwnProperty(type)) {
var Signal = process.binding('signal_wrap').Signal;
var wrap = new Signal();
wrap.unref();
wrap.onsignal = function() { process.emit(type); };
var signum = startup.lazyConstants()[type];
var r = wrap.start(signum);
if (r) {
wrap.close();
throw errnoException(process._errno, 'uv_signal_start');
}
signalWraps[type] = wrap;
}
return addListener.apply(this, arguments);
};
process.removeListener = function(type, listener) {
var ret = removeListener.apply(this, arguments);
if (isSignal(type)) {
assert(signalWraps.hasOwnProperty(type));
if (this.listeners(type).length === 0) {
signalWraps[type].close();
delete signalWraps[type];
}
}
return ret;
};
接下來是一個minimal module system
// core modules found in lib/*.js. All core modules are compiled into the
// node binary, so they can be loaded faster.
function NativeModule(id) {
this.filename = id + '.js';
this.id = id;
this.exports = {};
this.loaded = false;
}
NativeModule._source = process.binding('natives');
NativeModule._cache = {};
NativeModule.require = function(id) {
if (id == 'native_module') {
return NativeModule;
}
var cached = NativeModule.getCached(id);
if (cached) {
return cached.exports;
}
if (!NativeModule.exists(id)) {
throw new Error('No such native module ' + id);
}
process.moduleLoadList.push('NativeModule ' + id);
var nativeModule = new NativeModule(id);
nativeModule.cache();
nativeModule.compile();
return nativeModule.exports;
};
關注NativeModule的兩個prototype函數
NativeModule.prototype.compile = function() {
var source = NativeModule.getSource(this.id);
source = NativeModule.wrap(source);
var fn = runInThisContext(source, this.filename, true);
fn(this.exports, NativeModule.require, this, this.filename);
this.loaded = true;
};
NativeModule.prototype.cache = function() {
NativeModule._cache[this.id] = this;
};
反思:從Node.js的內部對象process,startup,NativeModule
在JavaScript的對象層面抽象了一些服務對象,而這些對象藉助於V8引擎和操作系統的底層實現
然後編譯對應的javascript代碼,實現服務端框架
在lib下面有具體的javascript代碼
根據node.js的說明,這些js代碼,應該被編譯到二進制代碼中,此前的錯誤應該是沒有把這部分的代碼編譯進入導致的。
上一篇的編譯錯誤
1> 系統找不到指定的路徑。
1> node_js2c
1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(151,5): error MSB6006: “cmd.exe”已退出,代碼爲 1。
========== 生成: 成功 0 個,失敗 1 個,最新 0 個,跳過 0 個 ==========
node_js2c的失敗,就導致了該部分的代碼無法正常運行
嘗試編譯
huareal@gpx /cygdrive/d/pbase/node-v0.10.16/tools
# ./js2c.py node_natives.c ../lib/*.*
編譯生成的node_natives.c大小達到2.57m
分析代碼跟node_natives.h中的內容差不多,看來應該把node.js也包含在lib中,全部編譯爲node_natives.h
將src/node.js複製到lib目錄下
然後運行
# ./js2c.py node_natives.h ../lib/*.*
將生成的node_natives.h複製到src目錄下,重新編譯
運行./node.exe hello.js
# ./node.exe hello.js
node.js:309
config = config.split('\n').slice(1).join('\n').replace(/'/g, '"');
^
TypeError: Cannot call method 'split' of undefined
at Function.startup.processConfig (node.js:309:21)
at startup (node.js:50:13)
at node.js:901:3
對應的代碼出錯行在node.js的50行
startup.processConfig();
嘗試屏蔽node.js中的該行代碼
// strip the gyp comment line at the beginning
//config = config.split('\n').slice(1).join('\n').replace(/'/g, '"');
重新生成node_natives.h
編譯測試
$ ./node.exe hello.js
undefined:1
undefined
^
SyntaxError: Unexpected token u
at Object.parse (native)
at Function.startup.processConfig (node.js:311:27)
at startup (node.js:50:13)
at node.js:901:3
有些莫名的錯誤,乾脆屏蔽代碼如下
startup.processConfig = function() {
// used for `process.config`, but not a real module
var config = NativeModule._source.config;
delete NativeModule._source.config;
// strip the gyp comment line at the beginning
//config = config.split('\n').slice(1).join('\n').replace(/'/g, '"');
/**
process.config = JSON.parse(config, function(key, value) {
if (value === 'true') return true;
if (value === 'false') return false;
return value;
});
*/
};
重新編譯測試
huareal@gpx /cygdrive/d/pbase/node-v0.10.16/Debug
$ ./node.exe hello.js
Server running at http://127.0.0.1:1337/
訪問測試:
成功hello world.