Perkenalkan dahulu perbezaan antara menggunakan API v8 dan menggunakan rangka kerja swig:
(1) Kaedah API v8 ialah kaedah asli yang disediakan oleh pegawai, dengan fungsi yang berkuasa dan lengkap. Kelemahannya ialah anda perlu biasa dengan API v8, yang lebih menyusahkan untuk ditulis kepada js dan tidak boleh menyokong bahasa skrip lain dengan mudah.
(2) swig ialah sokongan pihak ketiga, alat pembangunan komponen berkuasa yang menyokong penjanaan kod pembungkusan komponen C++ untuk pelbagai bahasa skrip biasa seperti python, lua, js, dsb. pengguna swig hanya perlu tulis kod C++ dan fail konfigurasi swig Anda boleh membangunkan komponen C++ dalam pelbagai bahasa skrip tanpa mengetahui rangka kerja pembangunan komponen pelbagai bahasa skrip Kelemahannya ialah ia tidak menyokong panggilan balik JavaScript, dokumentasi dan kod demo tidak lengkap, dan ada. tidak ramai pengguna.
1. JS Tulen untuk melaksanakan komponen Node.js
(1) Pergi ke direktori helloworld dan jalankan npm init untuk memulakan package.json Abaikan pelbagai pilihan dan biarkannya sebagai lalai.
(2) Indeks pelaksanaan komponen.js, contohnya:
module.exports.Hello = function(name) { console.log('Hello ' + name); }
(3) Jalankan dalam direktori luar: npm install ./helloworld, helloworld kemudiannya dipasang dalam direktori node_modules.
(4) Tulis kod penggunaan komponen:
var m = require('helloworld'); m.Hello('zhangsan'); //输出: Hello zhangsan
2. Gunakan API v8 untuk melaksanakan komponen JS - mod segerak
(1) Tulis binding.gyp, cth:
{ "targets": [ { "target_name": "hello", "sources": [ "hello.cpp" ] } ] }
(2) Tulis pelaksanaan komponen hello.cpp, cth:
#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) Susun komponen
node-gyp configure node-gyp build ./build/Release/目录下会生成hello.node模块。
(4) Tulis kod js ujian
const m = require('./build/Release/hello') console.log(m.foo()); //输出 Hello World
(5) Tambah package.json untuk pemasangan cth:
{ "name": "hello", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "node test.js" }, "author": "", "license": "ISC" }
(5) Pasang komponen pada node_modules
Pergi ke direktori atasan direktori komponen dan jalankan: npm install ./helloc //Nota: helloc ialah direktori komponen
Modul hello akan dipasang dalam direktori node_modules dalam direktori semasa Kod ujian ditulis seperti ini:
var m = require('hello'); console.log(m.foo());
3. Gunakan API v8 untuk melaksanakan komponen JS - mod tak segerak
Perihalan di atas ialah komponen segerak foo() ialah fungsi segerak, iaitu pemanggil fungsi foo() perlu menunggu fungsi foo() selesai dilaksanakan sebelum meneruskan apabila fungsi foo() adalah Operasi, fungsi IO yang memakan masa, fungsi foo() tak segerak boleh mengurangkan penantian menyekat dan meningkatkan prestasi keseluruhan.
Untuk melaksanakan komponen tak segerak, anda hanya perlu memberi perhatian kepada uv_queue_work API libuv Apabila melaksanakan komponen, kecuali kod utama hello.cpp dan kod pengguna komponen, bahagian lain adalah konsisten dengan tiga tunjuk cara di atas.
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::FunctionCallbackInfo; using v8::Function; using v8::Isolate; using v8::Local; using v8::Object; using v8::Value; using v8::Exception; using v8::Persistent; 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_tid_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->ThrowException(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) }
Idea asynchronous adalah sangat mudah Untuk melaksanakan fungsi kerja, fungsi penyiapan dan struktur yang membawa data untuk penghantaran lintasan, hanya hubungi uv_queue_work. Kesukarannya ialah kebiasaan dengan struktur data v8 dan 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 */
4. swig-javascript melaksanakan komponen Node.js
Gunakan rangka kerja swig untuk menulis komponen Node.js
(1) Tulis pelaksanaan komponen: *.h dan *.cpp
cth:
namespace a { class A{ public: int add(int a, int y); }; int add(int x, int y); }
(2) Tulis *.i, digunakan untuk menjana fail cpp pembungkusan swig
cth:
/* File : IExport.i */ %module my_mod %include "typemaps.i" %include "std_string.i" %include "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>; };
%apply di atas bermakna hasil int*, int* xx, std::string* result, std::string* yy, std::string& result dalam kod ialah perihalan output. Ini ialah peta taip pengganti.
Jika parameter penunjuk dalam parameter fungsi C++ mengembalikan nilai (dinyatakan melalui OUTPUT dalam fail *.i), Swig akan memprosesnya sebagai nilai pulangan fungsi JS Jika terdapat berbilang penunjuk, nilai pulangan fungsi JS adalah senarai.
%template(vectori) vector
(3) Tulis binding.gyp untuk kompilasi menggunakan node-gyp
(4) Hasilkan fail warpper cpp Beri perhatian kepada maklumat versi v8 semasa menjana, cth: swig -javascript -node -c++ -DV8_VERSION=0x040599 contoh.i
(5) Susun & uji
Kesukarannya terletak pada penggunaan jenis stl dan jenis tersuai Terdapat terlalu sedikit dokumen rasmi dalam hal ini.
swig - Penggunaan enkapsulasi JavaScript std::vector, std::string, lihat: Latihan saya, terutamanya memfokuskan pada pelaksanaan fail *.i.
5. Lain-lain
Apabila menggunakan API v8 untuk melaksanakan komponen Node.js, anda boleh menemui persamaan dengan melaksanakan komponen Lua Lua mempunyai mesin keadaan dan Node mempunyai Isolate.
Apabila Node melaksanakan eksport objek, ia perlu melaksanakan pembina, menambah "fungsi ahli" padanya, dan akhirnya mengeksport pembina sebagai nama kelas. Apabila Lua melaksanakan eksport objek, ia juga perlu melaksanakan fungsi kilang untuk mencipta objek, dan juga perlu menambah "fungsi ahli" pada jadual. Akhir sekali, eksport fungsi kilang.
Skrip js Node mempunyai kata kunci baharu, tetapi Lua tidak, jadi Lua hanya menyediakan kilang objek luaran untuk mencipta objek, manakala Node boleh menyediakan kilang objek atau enkapsulasi kelas.
Di atas adalah keseluruhan kandungan artikel ini, saya harap ia akan membantu kajian semua orang.