2016-06-03 8 views
2

Ich habe versucht, herauszufinden, wie asynchrone Anrufe in V8, ohne Glück zu machen. Das Beispiel JavaScript-Code Ich versuche laufen zu haben ist:V8 Javascript, wie asynchrone Anrufe

function test() 
{ 
    logMessage ('asynchronous call made!'); 
} 
saveFunc(test); 

Die saveFunc Funktion soll die Testfunktion für die Verwendung speichern, wenn der C++ Code ruft es später, nachdem das Skript ausgeführt wird. Jedes Mal, wenn ich es versuche, stürzt es ab, wenn ich versuche, die gespeicherte Funktion auszuführen. Was mache ich falsch?

Ich habe meinen gesamten Beispielcode unten kopiert. Danke im Voraus.

Beispielcode:

// Copyright 2015 the V8 project authors. All rights reserved. 
// Use of this source code is governed by a BSD-style license that can be 
// found in the LICENSE file. 

#include <iostream> 
#include <string> 

#include "libplatform/libplatform.h" 
#include "v8.h" 

using namespace v8; 

Local<Context> context; 
v8::Local<v8::Function> savedFunc; 

class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { 
public: 
    virtual void* Allocate(size_t length) { 
     void* data = AllocateUninitialized(length); 
     return data == NULL ? data : memset(data, 0, length); 
    } 
    virtual void* AllocateUninitialized(size_t length) { return malloc(length); } 
    virtual void Free(void* data, size_t) { free(data); } 
}; 

std::string parseV8Value(v8::Local<v8::Value> str) 
{ 
    if (str.IsEmpty() == true) 
     return (""); 

    v8::String::Utf8Value newStr(str); 

    return (*newStr); 
} 

void logMessage(const v8::FunctionCallbackInfo<v8::Value> &args) 
{ 
    std::string applicationSource = parseV8Value(args[0]); 
    std::cout << applicationSource << "\n"; 
} 

void getInput(const v8::FunctionCallbackInfo<v8::Value> &args) 
{ 
    v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast (args[0]); 
    std::string input = ""; 

    std::cin >> input; 

    v8::Local<v8::Value> *args2 = new v8::Local<v8::Value>[1]; 
    args2[0] = v8::String::NewFromUtf8 (args.GetIsolate(), input.c_str()); 

    func->Call (context->Global(), 1, args2); 

    delete []args2; 
    args2 = NULL; 
} 

void saveFunc(const v8::FunctionCallbackInfo<v8::Value> &args) 
{ 
    savedFunc = v8::Local<v8::Function>::Cast(args[0]); 
} 

int main(int argc, char* argv[]) { 
    // Initialize V8. 
    V8::InitializeICU(); 
    V8::InitializeExternalStartupData(argv[0]); 
    Platform* platform = platform::CreateDefaultPlatform(); 
    V8::InitializePlatform(platform); 
    V8::Initialize(); 

    // Create a new Isolate and make it the current one. 
    ArrayBufferAllocator allocator; 
    Isolate::CreateParams create_params; 
    create_params.array_buffer_allocator = &allocator; 
    Isolate* isolate = Isolate::New(create_params); 
    { 
     Isolate::Scope isolate_scope(isolate); 

     // Create a stack-allocated handle scope. 
     HandleScope handle_scope(isolate); 

     // Create a new context. 
     v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); 
     global->Set(v8::String::NewFromUtf8(isolate, "logMessage"), 
      v8::FunctionTemplate::New(isolate, logMessage)); 
     global->Set(v8::String::NewFromUtf8(isolate, "getInput"), 
      v8::FunctionTemplate::New(isolate, getInput)); 
     global->Set(v8::String::NewFromUtf8(isolate, "saveFunc"), 
      v8::FunctionTemplate::New(isolate, saveFunc)); 
     context = Context::New(isolate, NULL, global); 

     // Enter the context for compiling and running the hello world script. 
     Context::Scope context_scope(context); 

     // Create a string containing the JavaScript source code. 
     Local<String> source = 
      String::NewFromUtf8(isolate, 
      "function test(){ logMessage ('asynchronous call made!'); }saveFunc(test);",, 
       NewStringType::kNormal).ToLocalChecked(); 

     // Compile the source code. 
     Local<Script> script = Script::Compile(context, source).ToLocalChecked(); 

     // Run the script to get the result. 
     Local<Value> result = script->Run(context).ToLocalChecked(); 

     v8::Local<v8::Value> *args = new v8::Local<v8::Value>[0]; 
     savedFunc->Call(context->Global(), 0, args); 

     delete []args; 
     args = NULL; 
    } 

    // Dispose the isolate and tear down V8. 
    isolate->Dispose(); 
    V8::Dispose(); 
    V8::ShutdownPlatform(); 
    delete platform; 
    return 0; 
} 
+0

Ich bin mir nicht sicher, ob ich verstehe, was Sie versuchen zu tun. Soll 'saveFunc()' dasselbe tun wie ['process.nextTick()'] (https://nodejs.org/api/process.html#process_process_nexttick_callback_arg)? –

+0

Sie müssen unterscheiden zwischen lokalen und persistenten Handles: https://developers.google.com/v8/embed#handles-and-garbage-collection – AnatolyS

+1

Congraululations - Sie haben eine der Grundlagen von JavaScript, die die meisten Menschen entkommt - Nebenläufigkeit und asynchrone Aufrufe kommen nicht von JavaScript - sie kommen von der Host-Umgebung, um es wie Chromium oder Knoten zu wickeln - Node zum Beispiel fährt es mit LibUV. –

Antwort

3

Ok, so haben Sie eine persistente Verbindung zu verwenden, wenn die Funktion in saveFunc speichern. Außerdem müssen Sie sicherstellen, dass Sie beim Zugriff auf kontext-> global immer noch innerhalb des HandleScope sind. Hier ist der korrigierte Code:

// Copyright 2015 the V8 project authors. All rights reserved. 
// Use of this source code is governed by a BSD-style license that can be 
// found in the LICENSE file. 

#include <iostream> 
#include <string> 

#include "libplatform/libplatform.h" 
#include "v8.h" 

using namespace v8; 

Isolate* isolate = NULL; 
Local<Context> context; 
v8::Persistent<v8::Function> *savedFunc = NULL; 

class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { 
public: 
    virtual void* Allocate(size_t length) { 
     void* data = AllocateUninitialized(length); 
     return data == NULL ? data : memset(data, 0, length); 
    } 
    virtual void* AllocateUninitialized(size_t length) { return malloc(length); } 
    virtual void Free(void* data, size_t) { free(data); } 
}; 

std::string parseV8Value(v8::Local<v8::Value> str) 
{ 
    if (str.IsEmpty() == true) 
     return (""); 

    v8::String::Utf8Value newStr(str); 

    return (*newStr); 
} 

void logMessage(const v8::FunctionCallbackInfo<v8::Value> &args) 
{ 
    std::string applicationSource = parseV8Value(args[0]); 
    std::cout << applicationSource << "\n"; 
} 

void getInput(const v8::FunctionCallbackInfo<v8::Value> &args) 
{ 
    v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast (args[0]); 
    std::string input = ""; 

    std::cin >> input; 

    v8::Local<v8::Value> *args2 = new v8::Local<v8::Value>[1]; 
    args2[0] = v8::String::NewFromUtf8 (args.GetIsolate(), input.c_str()); 

    func->Call (context->Global(), 1, args2); 

    delete []args2; 
    args2 = NULL; 
} 

void saveFunc(const v8::FunctionCallbackInfo<v8::Value> &args) 
{ 
    v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(args[0]); 
    savedFunc = new v8::Persistent<v8::Function>(); 
    savedFunc->Reset(isolate, func); 
} 

int main(int argc, char* argv[]) { 
    // Initialize V8. 
    V8::InitializeICU(); 
    V8::InitializeExternalStartupData(argv[0]); 
    Platform* platform = platform::CreateDefaultPlatform(); 
    V8::InitializePlatform(platform); 
    V8::Initialize(); 

    // Create a new Isolate and make it the current one. 
    ArrayBufferAllocator allocator; 
    Isolate::CreateParams create_params; 
    create_params.array_buffer_allocator = &allocator; 
    isolate = Isolate::New(create_params); 
    { 
     Isolate::Scope isolate_scope(isolate); 

     // Create a stack-allocated handle scope. 
     HandleScope handle_scope(isolate); 

     // Create a new context. 
     v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); 
     global->Set(v8::String::NewFromUtf8(isolate, "logMessage"), 
      v8::FunctionTemplate::New(isolate, logMessage)); 
     global->Set(v8::String::NewFromUtf8(isolate, "getInput"), 
      v8::FunctionTemplate::New(isolate, getInput)); 
     global->Set(v8::String::NewFromUtf8(isolate, "saveFunc"), 
      v8::FunctionTemplate::New(isolate, saveFunc)); 
     context = Context::New(isolate, NULL, global); 

     // Enter the context for compiling and running the hello world script. 
     Context::Scope context_scope(context); 

     // The "asynchronous" javascript call to make 
     Local<String> source = 
      String::NewFromUtf8(isolate, 
    "function test(){ logMessage ('asynchronous call made!'); }saveFunc(test);", 
       NewStringType::kNormal).ToLocalChecked(); 

     // Compile the source code. 
     Local<Script> script = Script::Compile(context, source).ToLocalChecked(); 

     // Run the script to get the result. 
     Local<Value> result = script->Run(context).ToLocalChecked(); 

     v8::Local<v8::Value> *args = new v8::Local<v8::Value>[0]; 
     v8::Local<v8::Value> recv = context->Global(); 
     v8::Local<v8::Function> func = savedFunc->Get(isolate); 
     func->Call (recv, 0, args); 

     delete savedFunc; 
     savedFunc = NULL; 

     delete []args; 
     args = NULL; 
    } 

    // Dispose the isolate and tear down V8. 
    isolate->Dispose(); 
    V8::Dispose(); 
    V8::ShutdownPlatform(); 
    delete platform; 
    return 0; 
}