2016-06-03 2 views
2

Я пытался выяснить, как сделать асинхронные вызовы в V8 без везения. Пример Javascript код, который я пытаюсь иметь ПУСК:V8 javascript как сделать асинхронные вызовы

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

функция saveFunc предполагается сохранить функцию тестирования для использования, когда код C++ называет его позже после того, как скрипт побежал. Каждый раз, когда я пытаюсь это сделать, он срабатывает, когда я пытаюсь выполнить сохраненную функцию. Что я делаю не так?

Я скопировал весь код примера ниже. Заранее спасибо.

Пример кода:

// 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

Я не уверен, что понимаю, что вы пытаетесь сделать. это 'saveFunc()' предполагается делать то же самое, что ['process.nextTick()'] (https://nodejs.org/api/process.html#process_process_nexttick_callback_arg)? –

+0

Вы должны понимать differenct между локальными и постоянными дескрипторами: https://developers.google.com/v8/embed#handles-and-garbage-collection – AnatolyS

+1

Congradulations - вы выяснили одну из основ JavaScript, которая ускользает от большинства людей - параллелизм и асинхронные вызовы не исходят от JavaScript - они происходят из среды хоста, обертывая его, например, Chromium или Node - Node, например, диски с LibUV. –

ответ

3

Ok, так что вы должны использовать Persistent ручку при сохранении функции в saveFunc. Кроме того, вы должны убедиться, что, когда вы обращаетесь к контексту -> Global, вы все еще находитесь в HandleScope. Вот скорректированный код:

// 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; 
}