First, the difference between using the V8 API and using the Swig framework is described:
(1) V8 API mode for the official provision of the original method, powerful and perfect, the disadvantage is that the need to familiarize yourself with the V8 API, written up more trouble, is JS strong-related, not easy to support other scripting languages.
(2) Swig for Third-party support, a powerful component development tool, support for Python, Lua, JS and other common scripting languages to generate C + + component packaging code, swig users only need to write C + + code and Swig configuration files to develop a variety of scripting language C + + components, There is no need to understand the component development framework for various scripting languages, but the drawback is that JavaScript callbacks are not supported, the documentation and demo codes are imperfect, and there are few users.
A, pure JS implementation Node.js components
(1) to the HelloWorld directory to perform NPM init initialization Package.json, the various options first, the default can be.
(2) The implementation index.js of the component, for example:
Module.exports.Hello = function (name) {
console.log (' Hello ' + name);
}
(3) execution in the outer directory: NPM install./helloworld,helloworld was then installed in the Node_modules directory.
(4) Writing components using code:
var m = require (' HelloWorld ');
M.hello (' Zhangsan ');
Output: Hello Zhangsan
Second, use V8 API to implement JS component--Synchronous mode
(1) Writing binding.gyp, eg:
{
"targets": [
{
"target_name": "Hello",
"sources": ["Hello.cpp"]
}
]
}
(2) Write the implementation of the component Hello.cpp,eg:
#include <node.h>
namespace Cpphello {
using V8::functioncallbackinfo;
Using V8::isolate;
Using V8::local;
Using V8::object;
Using V8::string;
Using V8::value;
void Foo (const functioncallbackinfo<value>& args) {
isolate* isolate = args. Getisolate ();
Args. Getreturnvalue (). Set (String::newfromutf8 (Isolate, "Hello World"));
}
void Init (Local<object> exports) {
Node_set_method (exports, "foo", foo);
}
Node_module (Cpphello, Init)
}
(3) Compiling components
The Hello.node module is generated in the Node-gyp configure NODE-GYP build./build/release/directory.
(4) Write test JS code
Const M = require ('./build/release/hello ')
Console.log (M.foo ());//Output Hello World
(5) Increase Package.json for the installation of eg:
{
"name": "Hello", "
Version": "1.0.0",
"description": "",
"main": "Index.js", "
scripts": {
"Test": "Node Test.js"
},
"author": "",
"license": "ISC"
}
(5) Install components to Node_modules
Go to the parent directory of the component directory, execute: NPM install./helloc//NOTE: Helloc as component directory
The Hello module is installed in the Node_modules directory under the current directory, and the code is tested to write this:
var m = require (' hello ');
Console.log (M.foo ());
Using V8 API to implement JS component--Asynchronous mode
The synchronization component is described above, foo () is a synchronous function in which the caller of the Foo () function waits for the Foo () function to go down, and when the Foo () function is an IO-time-consuming operation, the asynchronous Foo () function can reduce blocking waiting and improve overall performance.
The implementation of the asynchronous component only needs to pay attention to the LIBUV uv_queue_work API, the component implementation, in addition to the main code hello.cpp and component user code, the other parts are consistent with the above three demo.
Hello.cpp:
* * Node.js CPP Addons Demo:async call and call back.
* GCC 4.8.2 * AUTHOR:CSWUYG * date:2016.02.22 * * */#include <iostream> #include <node.h> #include <uv.h> #include <sstream> #include <unistd.h> #include <pthread.h> namespace Cpphello {using v8::function
Callbackinfo;
Using V8::function;
Using V8::isolate;
Using V8::local;
Using V8::object;
Using V8::value;
Using V8::exception;
Using V8::P ersistent;
Using V8::handlescope;
Using V8::integer;
Using V8::string;
Async task struct mytask{uv_work_t work;
int a{0};
int b{0};
int output{0};
unsigned long long work_tid{0};
unsigned long long main_tid{0};
Persistent<function> callback;
};
Async function void Query_async (uv_work_t* work) {mytask* task = (mytask*) work->data;
Task->output = Task->a + task->b;
Task->work_tid = Pthread_self (); Usleep (1000 * 1000 * 1); 1 Second}//Async compleTe callback void Query_finish (uv_work_t* work, int status) {isolate* isolate = isolate::getcurrent ();
Handlescope Handle_scope (isolate);
mytask* task = (mytask*) work->data;
const unsigned int argc = 3;
Std::stringstream stream;
Stream << task->main_tid;
std::string main_tid_s{stream.str ()};
Stream.str ("");
Stream << task->work_tid;
std::string work_tid_s{stream.str ()}; Local<value> ARGV[ARGC] = {integer::new (isolate, Task->output), String::newfromutf8 (Isolate, main_t
Id_s.c_str ()), String::newfromutf8 (Isolate, Work_tid_s.c_str ())}; Local<function>::new (Isolate, Task->callback)->call (Isolate->getcurrentcontext ()->Global (),
ARGC, argv); Task->callback.
Reset ();
Delete task; }//Async main void Async_foo (const functioncallbackinfo<value>& args) {isolate* isolate = args.
Getisolate ();
Handlescope Handle_scope (isolate); if (aRGs. Length ()!= 3) {isolate->throwexception (Exception::typeerror (String::newfromutf8 (Isolate, "Arguments Num:3"))
;
Return } if (!args[0]->isnumber () | |!args[1]->isnumber () | |!args[2]->isfunction ()) {ISOLATE->THROWEXCEP
tion (Exception::typeerror (String::newfromutf8 (Isolate, "arguments error"));
Return
} mytask* my_task = new MyTask;
My_task->a = Args[0]->tointeger ()->value ();
My_task->b = Args[1]->tointeger ()->value (); My_task->callback.
Reset (Isolate, Local<function>::cast (args[2));
My_task->work.data = My_task;
My_task->main_tid = Pthread_self ();
uv_loop_t *loop = Uv_default_loop ();
Uv_queue_work (Loop, &my_task->work, Query_async, query_finish);
} void Init (Local<object> exports) {Node_set_method (exports, "foo", Async_foo);
} node_module (Cpphello, Init)}
Asynchronous thinking is very simple, the implementation of a work function, a completion function, a host of data across the thread transmission structure, call Uv_queue_work can. The difficulty is familiarity with the V8 data structure and API.
Test.js
Test Hellouv Module
' use strict ';
Const M = require (' Hellouv ')
M.foo (1, 2, (A, B, c) =>{
console.log (' Finish job: ' + a ');
Console.log (' main thread: ' + B ');
Console.log (' Work thread: ' + c);
});
/* Output:
finish job:3
main thread:139660941432640
work thread:139660876334848
* *
Iv. Swig-javascript Implementation of Node.js components
Writing Node.js components using the SWIG framework
(1) Compile the implementation of the components: *.h and *.cpp
eg
Namespace a {
class a{public
:
int Add (int a, int y);
int add (int x, int y);
}
(2) Write *.i to generate Swig packing CPP file
eg
* * File:iexport.i/%module my_mod%include "typemaps.i"%include "STD_STRING.I"%inc
Lude "std_vector.i"%{#include "export.h"%}%apply int *output {int *result, int* xx};
%apply std::string *output {std::string* result, std::string* yy};
%apply std::string &output {std::string& result};
%include "Export.h" namespace std {%template (Vectori) vector<int>;
%template (VECTORSTR) vector<std::string>;
};
The above%apply represents the int* result in the code, int* xx, std::string* result, std::string* yy, and std::string& result is the output description, which is typemap and is a substitution.
C + + function parameters in the pointer parameters, if the return value (through the *.i file in the output specified), Swig will treat them as the return value of the JS function, if there are more than one pointer, then the return value of the JS function is list.
%template (Vectori) vector<int> indicates that a type Vectori is defined for JS, which is usually used as a parameter or return value by C + + functions, and it needs to be used when writing JS code.
(3) Writing binding.gyp for use with NODE-GYP compilation
(4) Generate Warpper CPP file Generation Note V8 version information, eg:swig-javascript-node-c++-dv8_version=0x040599 example.i
(5) Compiling & Testing
The difficulty is in the use of STL types, custom types, and too few official documents.
Swig-javascript to Std::vector, std::string, encapsulation use see: My practice, the main focus on *.I file implementation.
v. Other
when implementing the Node.js component using the V8 API, you can find similarities to the LUA component, LUA has a state machine, node has isolate.
When node implements an object export, it needs to implement a constructor, add "member functions" to it, and finally export the constructor to the class name. When Lua implements object export, it also needs to implement a factory function that creates objects, as well as adding "member functions" to the table. Finally, the factory function is exported.
Node's JS script has the new keyword, LUA does not, so LUA only provides object factories to create objects, and node can provide object factories or class encapsulation.
The above is the entire content of this article, I hope to help you learn.