Js解释器V8引擎嵌入的异常处理

v8引擎为Google开发的JS语言解释器有着高效易用等特点,通常它执行一个Js脚本需要经过编译和运行步骤,

由于我们的脚本程序很可能不正确,随时造成过程环节的异常,我们来解决一个异常以及错误的捕捉和处理过程,如下脚本:

test.js:

var str = 'Hello';
str
= str + ', World!';
alert(str);

  

使用以下经典的V8 C++示例代码来执行脚本:

#include <v8.h>
using namespace v8;

//提取js文件
v8::Handle<v8::String> ReadFile(const char* name)
{
FILE
* file = fopen(name, "rb");
if (file == NULL) return v8::Handle<v8::String>();
fseek(file,
0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size]
= '\0';
for (int i = 0; i < size;)
{
int read = fread(&chars[i], 1, size - i, file);
i
+= read;
}
fclose(file);
v8::Handle
<v8::String> result = v8::String::New(chars, size);
delete[] chars;
return result;
}

int main()
{
HandleScope handle_scope;
Handle
<Context> context = Context::New();
Context::Scope context_scope(context);

const char * fname = "test.js";
Handle
<String> source = ReadFile(fname);
//ExecuteString(source, String::New(fname), true, true);

Handle
<Script> script = Script::Compile(source);
Handle
<Value> result = script->Run();
String::AsciiValue ascii(result);
printf(
"%s\n", *ascii);
return 0;
}

 

然后编译程序 

# g++ -o test test.cpp -lv8 

# ./test

<unknown>:58: Uncaught ReferenceError: alert is not defined

Segmentation fault

在执行过程遇到JS语法错误时,V8很干脆地中上了进程,提醒段错误。

在这我们正常应用环境是无法使用的,需要有一种异常处理机制来收集并处理错误。

这就是v8::TryCatch ,在编译前声明,在之后的编译和执行中只要有错误的发生均可捕获。

查找了相关的V8源代码,改进后的代码实现如下(函数体),

其中source为源文件内容,name用来标记当前脚本名称(文件名),

print_result表示是否打印脚本执行结果,report_exceptions表示是否报告异常(错误):

 

bool ExecuteString(v8::Handle<v8::String> source,
v8::Handle
<v8::Value> name,
bool print_result,
bool report_exceptions)
{
v8::HandleScope handle_scope;
v8::TryCatch try_catch;
//这里设置异常机制
v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
if (script.IsEmpty()) {
// Print errors that happened during compilation.
if (report_exceptions)
ReportException(
&try_catch);
return false;
}
else {
v8::Handle
<v8::Value> result = script->Run();
if (result.IsEmpty()) {
assert(try_catch.HasCaught());
// Print errors that happened during execution.
if (report_exceptions)
ReportException(
&try_catch);
return false;
}
else {
assert(
!try_catch.HasCaught());
if (print_result && !result->IsUndefined()) {
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::Utf8Value str(result);
const char* cstr = ToCString(str);
printf(
"%s\n", cstr);
}
return true;
}
}
}

 

相关的异常处理函数:

 

const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}


void ReportException(v8::TryCatch* try_catch) {
v8::HandleScope handle_scope;
v8::String::Utf8Value exception(try_catch
->Exception());
const char* exception_string = ToCString(exception);
v8::Handle
<v8::Message> message = try_catch->Message();
if (message.IsEmpty()) {
// V8 didn't provide any extra information about this error; just
// print the exception.
printf("%s\n", exception_string);
}
else {
// Print (filename):(line number): (message).
v8::String::Utf8Value filename(message->GetScriptResourceName());
const char* filename_string = ToCString(filename);
int linenum = message->GetLineNumber();
printf(
"%s:%i: %s\n", filename_string, linenum, exception_string);
// Print line of source code.
v8::String::Utf8Value sourceline(message->GetSourceLine());
const char* sourceline_string = ToCString(sourceline);
printf(
"%s\n", sourceline_string);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn();
for (int i = 0; i < start; i++) {
printf(
" ");
}
int end = message->GetEndColumn();
for (int i = start; i < end; i++) {
printf(
"^");
}
printf(
"\n");
v8::String::Utf8Value stack_trace(try_catch
->StackTrace());
if (stack_trace.length() > 0) {
const char* stack_trace_string = ToCString(stack_trace);
printf(
"%s\n", stack_trace_string);
}
}
}

 

最后修改main入口:
int main(int argc, char* argv[])
{
HandleScope handle_scope;

Handle
<Context> context = Context::New();
Context::Scope context_scope(context);

const char * fname = "test.js";
Handle
<String> source = ReadFile(fname);
ExecuteString(source, String::New(fname),
true, true);

return 0;
}

  

重新编译后运行结果为:

# ./test

test.js:3: ReferenceError: alert is not defined

alert(str);

^

ReferenceError: alert is not defined

    at test.js:3:1

已经可以正常报告错误。

posted @ 2011-08-10 16:06  lajabs  阅读(2896)  评论(1编辑  收藏  举报