请教问题:Nodejs 编写的addon内 如何通过V8引擎运行JS代码
请教问题:Nodejs 编写的addon内 如何通过V8引擎运行JS代码
###run.cpp:
#define BUILDING_NODE_EXTENSION
#include <node.h>
using namespace v8;
Handle<Value> run(const Arguments& args) {
HandleScope scope;
if (args.Length() < 1) {
ThrowException(Exception::TypeError(String::New("Args Error")));
return scope.Close(Undefined());
}
if (!args[0]->IsString()) {
ThrowException(Exception::TypeError(String::New("Args Error")));
return scope.Close(Undefined());
}
Persistent<Context> context = Context::New();
Context::Scope context_scope(context);
Local<Script> scritp = Script::Compile(args[0]->ToString());
Local<Value> result = scritp->Run();
return scope.Close(result);
}
void Init(Handle<Object> exports) {
exports->Set(String::NewSymbol("run"),
FunctionTemplate::New(run)->GetFunction());
}
NODE_MODULE(run, Init)
###test.js:
var addons = require('./run.node');
addons.run("console.log('hello world')");
###运行
使用命令:node test.js 报错:
ReferenceError: console is not defined
at <anonymous>:1:1
at Object.<anonymous> (C:\Users\fx\Documents\Visual Studio 2010\Projects\helloworld\Debug\test.js:2:8)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:902:3
也不知道是啥问题,跪求高手现身
你遇到的问题是因为你在V8上下文中运行的JavaScript代码中尝试访问全局对象global
中的一些内置对象(如console
),但这些对象并没有被自动包含在你的V8上下文中。为了解决这个问题,你需要手动创建并添加这些全局对象到你的V8上下文中。
下面是修改后的run.cpp
文件示例:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include <v8.h>
using namespace v8;
Handle<Value> run(const Arguments& args) {
HandleScope scope;
if (args.Length() < 1) {
ThrowException(Exception::TypeError(String::New("Args Error")));
return scope.Close(Undefined());
}
if (!args[0]->IsString()) {
ThrowException(Exception::TypeError(String::New("Args Error")));
return scope.Close(Undefined());
}
// 创建一个新的V8上下文
Persistent<Context> context = Context::New();
Context::Scope context_scope(context);
// 创建一个全局对象模板
Local<ObjectTemplate> globalTpl = ObjectTemplate::New();
// 添加console对象到全局对象模板中
globalTpl->Set(String::New("console"), FunctionTemplate::New(ConsoleLog));
// 使用全局对象模板创建新的全局对象
Local<Object> globalObj = globalTpl->NewInstance();
// 将全局对象添加到当前V8上下文中
Context::Scope context_scope(context);
context->Global()->Set(String::New("global"), globalObj);
// 编译并运行JavaScript代码
Local<Script> script = Script::Compile(args[0]->ToString());
Local<Value> result = script->Run();
return scope.Close(result);
}
// 定义console.log函数
void ConsoleLog(const FunctionCallbackInfo<Value>& args) {
for (int i = 0; i < args.Length(); i++) {
printf("%s ", *String::Utf8Value(args[i]->ToString()));
}
printf("\n");
}
void Init(Handle<Object> exports) {
exports->Set(String::NewSymbol("run"),
FunctionTemplate::New(run)->GetFunction());
}
NODE_MODULE(run, Init)
在上述代码中,我们定义了一个ConsoleLog
函数来模拟console.log
的行为,并将其添加到全局对象模板中。然后,我们将这个全局对象模板实例化为一个新的全局对象,并将其设置为当前V8上下文的全局对象。这样,当我们在V8上下文中运行JavaScript代码时,就可以正确地访问console
对象了。
请注意,为了使这段代码工作,你需要将ConsoleLog
函数定义为void ConsoleLog(const FunctionCallbackInfo<Value>& args)
的形式,并确保它能够处理传入的参数。在这个例子中,我们只是简单地打印了传递给它的所有参数。
可能 原因是console 不是标准的js库,你试试addons.run("‘Hello’ + ‘, World!’");看看结果是不是Hello,World
嗯,确实是这样,但是我想实现的功能类似于这里的 module._compile 方法,这个方法能将文件读入后compile成function。
// Native extension for .js
Module._extensions['.js'] = function(module, filename) {
var content = NativeModule.require('fs').readFileSync(filename, 'utf8');
module._compile(stripBOM(content), filename);
};
你遇到的问题是因为在你编译的 Script
中没有创建全局上下文,因此 console
对象未被定义。你需要确保在编译脚本时包含全局上下文。
你可以修改你的 run.cpp
文件,使它包含一个完整的 V8 上下文。以下是修改后的代码:
#define BUILDING_NODE_EXTENSION
#include <node.h>
using namespace v8;
Handle<Value> run(const Arguments& args) {
HandleScope scope;
if (args.Length() < 1) {
ThrowException(Exception::TypeError(String::New("Args Error")));
return scope.Close(Undefined());
}
if (!args[0]->IsString()) {
ThrowException(Exception::TypeError(String::New("Args Error")));
return scope.Close(Undefined());
}
// 创建一个新的上下文并进入该上下文
Persistent<Context> context = Context::New();
Context::Scope context_scope(context);
// 创建全局对象模板
Local<ObjectTemplate> global = ObjectTemplate::New();
global->Set(String::New("console"), FunctionTemplate::New(consoleLog));
// 创建新上下文并设置全局对象模板
Persistent<Context> persistent_context = Context::New(isolate, NULL, global);
Context::Scope context_scope(persistent_context);
// 编译并运行脚本
Local<String> source = args[0]->ToString();
Local<Script> script = Script::Compile(source);
Local<Value> result = script->Run();
// 清理
persistent_context.Dispose();
persistent_context.Clear();
return scope.Close(result);
}
// 定义 console.log 函数
Local<Value> consoleLog(const Arguments& args) {
for (int i = 0; i < args.Length(); i++) {
printf("%s\n", *String::AsciiValue(args[i]->ToString()));
}
return Undefined();
}
void Init(Handle<Object> exports) {
exports->Set(String::NewSymbol("run"),
FunctionTemplate::New(run)->GetFunction());
}
NODE_MODULE(run, Init)
在这个示例中,我们定义了一个新的 consoleLog
函数,并将其添加到全局对象模板中。这样可以确保 console
对象在编译的脚本中可用。
然后你可以像之前一样运行你的 test.js
脚本,应该不会再出现 ReferenceError
错误了。