Node.js memiliki efek terbaik dalam menulis backend menggunakan JavaScript, dan ada baiknya mencoba lebih banyak. Namun, jika Anda membutuhkan beberapa fungsi yang tidak dapat digunakan secara langsung atau bahkan modul yang tidak dapat diimplementasikan sama sekali, dapatkah Anda memperkenalkan pencapaian tersebut dari perpustakaan C/C ++? Jawabannya adalah ya. Yang harus Anda lakukan adalah menulis plugin dan menggunakan sumber daya dasar kode lainnya dalam kode JavaScript Anda. Mari kita mulai pertanyaan pertanyaan hari ini bersama.
memperkenalkan
Seperti yang dikatakan Node.js dalam dokumentasi resmi, plug-in adalah objek yang dibagikan yang ditautkan secara dinamis, yang dapat menghubungkan kode JavaScript dengan perpustakaan C/C ++. Ini berarti kita dapat merujuk apa saja dari perpustakaan C/C ++ dan memasukkannya ke dalam node.js dengan membuat plugin.
Sebagai contoh, kami akan membuat enkapsulasi untuk objek std std :: string standar.
Persiapan
Sebelum kita mulai menulis, kita perlu memastikan bahwa kita telah menyiapkan semua bahan yang dibutuhkan untuk kompilasi modul berikutnya. Setiap orang membutuhkan Node-Gyp dan semua dependensi. Anda dapat menggunakan perintah berikut untuk menginstal Node-Gyp:
NPM Instal -g Node -Gyp
Dalam hal ketergantungan, kita perlu menyiapkan proyek -proyek berikut untuk sistem UNIX: • Python (membutuhkan versi 2.7, 3.x tidak dapat bekerja dengan baik)
• membuat
• Toolchain C ++ Compiler (seperti GPP atau G ++)
Misalnya, di Ubuntu, Anda dapat menggunakan perintah berikut untuk menginstal semua proyek di atas (Python 2.7 seharusnya sudah diinstal sebelumnya):
sudo apt-get install build-esentials
Di lingkungan Sistem Windows, yang Anda butuhkan adalah:
• Python (Versi 2.7.3, 3.x tidak dapat bekerja secara normal)
• Microsoft Visual Studio C ++ 2010 (untuk Windows XP/Vista)
• Microsoft Visual Studio C ++ 2012 untuk Windows Desktop (untuk Windows 7/8)
Untuk menekankan, versi Express dari Visual Studio juga dapat bekerja secara normal.
file binding.gyp
File ini digunakan oleh Node-Gyp dan dirancang untuk menghasilkan file build yang sesuai untuk plugin kami. Anda dapat mengklik di sini untuk melihat dokumen deskripsi file .gyp yang disediakan oleh Wikipedia, tetapi contoh yang ingin kami gunakan hari ini sangat sederhana, jadi Anda hanya perlu menggunakan kode berikut:
{"target": [{"target_name": "stdString", "sumber": ["addon.cc", "stdstring.cc"]}]}di mana target_name dapat diatur ke apa pun yang Anda suka. Array sumber berisi semua file sumber yang perlu digunakan plug-in. Dalam contoh kami, addon.cc juga disertakan, yang digunakan untuk mengakomodasi kode yang diperlukan untuk mengkompilasi plugin dan stdstring.cc, ditambah kelas enkapsulasi kami.
Kelas StdStringWrapper
Langkah pertama adalah mendefinisikan kelas kita sendiri di file stdstring.h. Jika Anda terbiasa dengan pemrograman C ++, Anda pasti tidak akan tidak terbiasa dengan dua baris kode berikut.
#ifndef stdstring_h #define stdstring_h
Ini milik standar termasuk penjaga. Selanjutnya, kita perlu memasukkan dua header berikut dalam kategori termasuk:
#termasuk
#termasuk
Yang pertama ditujukan pada kelas STD :: String, sedangkan yang kedua termasuk bertindak pada semua node dan konten terkait V8.
Setelah langkah ini selesai, kami dapat mendeklarasikan kelas kami:
kelas stdStringwrapper: node publik :: objectwrap {
Untuk semua kelas yang ingin kami sertakan dalam plugin, kami harus memperluas Node :: ObjectWrap kelas.
Sekarang kita dapat mulai mendefinisikan properti pribadi kelas ini:
Private: std :: string* s_; eksplisit stdstringwrapper (std :: string s = ""); ~ StdStringwrapper ();
Selain konstruktor dan fungsi analitik, kita juga perlu mendefinisikan pointer untuk std :: string. Ini adalah inti dari teknologi ini dan dapat digunakan untuk menghubungkan basis kode C/C ++ ke Node - kami mendefinisikan pointer pribadi untuk kelas C/C ++ dan akan menggunakan pointer ini untuk mengimplementasikan operasi dalam semua metode selanjutnya.
Sekarang kami mendeklarasikan properti statis konstruktor, yang akan menyediakan fungsi untuk kelas yang kami buat di v8:
Static v8 :: konstruktor persisten;
Teman yang berminat dapat mengklik di sini untuk merujuk pada rencana deskripsi template untuk detail lebih lanjut.
Sekarang kita juga membutuhkan metode baru, yang akan ditugaskan ke konstruktor yang disebutkan di atas, dan V8 akan menginisialisasi kelas kita:
statis v8 :: menangani baru (const v8 :: argumen & args);
Setiap fungsi yang bertindak pada V8 harus mengikuti persyaratan berikut: Ini akan menerima referensi ke V8 :: Argumen Objek dan mengembalikan V8 :: Handle> V8 :: Value>-Ini persis bagaimana V8 berurusan dengan JavaScript tipe lemah saat menggunakan pengkodean C ++ tipe kuat.
Setelah ini, kita perlu memasukkan dua metode lain ke dalam prototipe objek:
statis v8 :: handle add (const v8 :: argumen & args); statis v8 :: menangani tostring (const v8 :: argumen & args);
Di mana metode ToString () memungkinkan kita untuk mendapatkan nilai S_, bukan nilai [objek objek] saat menggunakannya dengan string JavaScript normal.
Akhirnya, kami akan memperkenalkan metode inisialisasi (metode ini akan dipanggil oleh V8 dan ditugaskan ke fungsi konstruktor) dan tutup termasuk penjaga:
Publik: static void init (v8 :: menangani ekspor); }; #endif
Peran objek Ekspor dalam modul JavaScript setara dengan modul. Exports.
file stdstring.cc, fungsi konstruktor dan parsing
Sekarang buat file stdstring.cc. Pertama -tama kita harus memasukkan header kami:
#include "stdstring.h"
Berikut ini mendefinisikan properti untuk konstruktor (karena itu termasuk fungsi statis):
v8 :: stdstringwrapper gigih :: konstruktor;
Konstruktor ini melayani kelas akan menetapkan atribut S_:
StdStringwrapper :: stdStringWrapper (std :: string s) {s_ = std :: string (s) baru; }Dan fungsi parsing akan menghapusnya untuk menghindari overflow memori:
StdStringwrapper :: ~ stdStringWrapper () {delete s_; }Selain itu, Anda harus menghapus semua konten yang ditetapkan dengan yang baru, karena setiap kali situasi seperti itu dapat menyebabkan pengecualian, harap ingat operasi di atas atau menggunakan pointer bersama.
Metode init
Metode ini akan dipanggil oleh V8 dan dimaksudkan untuk menginisialisasi kelas kami (tetapkan konstruktor, dan tempatkan semua konten yang ingin kami gunakan dalam JavaScript dalam objek Ekspor):
void stdStringwrapper :: init (v8 :: handle exports) {
Pertama, kita perlu membuat templat fungsi untuk metode baru kita:
v8 :: tpl lokal = v8 :: functionTemplate :: new (baru);
Ini sedikit mirip dengan fungsi baru di JavaScript - memungkinkan kita untuk menyiapkan kelas JavaScript kita sendiri.
Sekarang kita dapat mengatur nama untuk fungsi sesuai dengan kebutuhan aktual (jika Anda melewatkan langkah ini, konstruktor akan dalam keadaan anonim, yaitu, namanya berfungsi somename () {} atau function () {}):
tpl-> setClassName (v8 :: string :: newsymbol ("stdString"));
Kami menggunakan v8 :: string :: newsymbol () untuk membuat string tipe khusus untuk nama properti - yang menghemat sedikit waktu untuk operasi mesin.
Setelah ini, kita perlu menetapkan berapa banyak bidang yang berisi instance kelas kita:
tpl-> instanceTemplate ()-> setinternalfieldcount (2);
Kami memiliki dua metode - add () dan tostring (), jadi kami mengatur nomor ke 2. Sekarang kami dapat menambahkan metode kami sendiri ke prototipe fungsi:
tpl-> prototipeTemplate ()-> set (v8 :: string :: newsymbol ("add"), v8 :: functionTemplate :: new (add)-> getFunction ());
tpl-> prototipeTemplate ()-> set (v8 :: string :: newsymbol ("tostring"), v8 :: functionTemplate :: new (toString)-> getFunction ());
Bagian kode ini terlihat cukup besar, tetapi selama Anda mengamati dengan hati-hati, Anda akan menemukan aturannya: kami menggunakan TPL-> ProtoTyPetemplate ()-> Set () untuk menambahkan setiap metode. Kami juga menggunakan v8 :: string :: newsymbol () untuk memberi mereka nama dan functionTemplate.
Akhirnya, kita dapat menempatkan konstruktor di objek Ekspor dalam properti kelas konstruktor kami:
constructor = v8 :: persistent :: new (tpl-> getFunction ()); ekspor-> set (v8 :: string :: newsymbol ("stdString"), konstruktor); }Metode baru
Sekarang yang harus kita lakukan adalah mendefinisikan metode yang berfungsi sama dengan objek javascript.prototype.constructor:
v8 :: menangani stdstringwrapper :: new (const v8 :: argumen & args) {Pertama -tama kita perlu membuat ruang untuk itu:
V8 :: Cakupan Handlescope;
Setelah ini, kita dapat menggunakan metode .isconstructCall () dari objek ARGS untuk memeriksa apakah konstruktor dapat dipanggil menggunakan kata kunci baru:
if (args.isconstructcall ()) {Jika Anda bisa, pertama -tama kami meneruskan parameter ke std :: string sebagai berikut:
v8 :: string :: utf8value str (args [0]-> tostring ()); std :: string s (*str);
... jadi kita bisa meneruskannya ke konstruktor kelas yang dienkapsulasi:
StdStringwrapper* obj = stdStringwrapper baru;
Setelah ini, kita dapat menggunakan metode .wrap () dari objek yang kita buat sebelumnya (diwarisi dari Node :: ObjectWrap) untuk menetapkannya ke variabel ini:
obj-> wrap (args.this ());
Akhirnya, kita dapat mengembalikan objek yang baru dibuat ini:
return args.ini ();
Jika fungsi tidak dapat dipanggil dengan yang baru, kita juga dapat menghubungi konstruktor secara langsung. Selanjutnya, yang ingin kami lakukan adalah mengatur konstanta untuk jumlah parameter:
} else {const int argc = 1;Sekarang kita perlu membuat array menggunakan parameter kita sendiri:
v8 :: argv lokal [argc] = {args [0]};Kemudian lulus hasil dari konstruktor-> metode newinstance untuk cakupan. Lose sehingga objek dapat memainkan peran nanti (ruang lingkup. CLOSE pada dasarnya memungkinkan semua orang untuk mempertahankannya dengan memindahkan pegangan pemrosesan objek ke kisaran yang lebih tinggi - ini juga bagaimana fungsi berlaku):
return scope.close (konstruktor-> newinstance (argc, argv)); }}
tambahkan metode
Sekarang mari kita buat metode add, yang dimaksudkan untuk memungkinkan semua orang menambahkan konten ke std internal objek :: string:
v8 :: menangani stdstringwrapper :: add (const v8 :: argumen & args) {Pertama, kita perlu membuat rentang untuk fungsi kita dan mengubah parameter menjadi std :: string seperti sebelumnya:
V8 :: Cakupan Handlescope; v8 :: string :: utf8value str (args [0]-> tostring ()); std :: string s (*str);
Sekarang kita perlu membongkar objek. Kami juga telah melakukan operasi enkapsulasi terbalik ini sebelumnya - kali ini kami akan mendapatkan pointer ke objek dari variabel ini.
StdStringwrapper* obj = objectwrap :: unwrap (args.this ());
Kemudian kita dapat mengakses atribut S_ dan menggunakan metode .Append ():
obj-> s _-> append (s);
Akhirnya, kami mengembalikan nilai saat ini dari atribut S_ (perlu menggunakan scope.close lagi):
return scope.close (v8 :: string :: new (obj-> s _-> c_str ()));
Karena metode v8 :: string :: new () hanya dapat menerima pointer char sebagai nilai, kita perlu menggunakan obj-> s _-> c_str () untuk mendapatkannya.
Pada saat ini, direktori build harus dibuat di folder plug-in Anda.
tes
Sekarang kita dapat menguji plug-in kita. Buat file test.js dan pustaka kompilasi yang diperlukan di direktori plug-in kami (Anda dapat langsung melewatkan ekstensi .node):
var addon = membutuhkan ('./ Bangun/rilis/addon');Selanjutnya, buat instance baru untuk objek kami:
var test = addon.stdstring baru ('tes');Selanjutnya, lakukanlah, seperti menambahkan atau mengubahnya menjadi string:
test.add ('!'); Console.log ('Test/' S Dontents: %S ', test);Setelah berjalan, Anda akan melihat hasil eksekusi berikut di konsol:
sebagai kesimpulan
Saya harap setelah membaca tutorial ini, Anda dapat menghilangkan kekhawatiran Anda dan menganggap membuat dan menguji plug-in Node.js yang disesuaikan berdasarkan perpustakaan C/C ++ sebagai tugas yang sangat sulit. Anda dapat menggunakan teknologi ini untuk dengan mudah memperkenalkan hampir semua perpustakaan C/C ++ ke Node.js. Jika Anda mau, Anda juga dapat menambahkan lebih banyak fungsi ke plug-in sesuai dengan kebutuhan aktual. STD :: String menyediakan banyak metode, dan kami dapat menggunakannya sebagai bahan latihan.
Tautan praktis
Teman yang tertarik dapat memeriksa tautan berikut untuk lebih banyak sumber daya dan detail yang terkait dengan pengembangan plug-in node.js, perpustakaan loop acara V8 dan C.
• Dokumentasi plugin Node.js
• Dokumentasi V8
• Libuv (Perpustakaan Lingkaran Acara C), dari GitHub
Bahasa Inggris: http://code.tutsplus.com/tutorials/writing-nodejs-addons--cms-21771