Node.js มีผลที่ดีที่สุดในการเขียนแบ็กเอนด์โดยใช้ JavaScript และคุ้มค่าที่จะลองมากกว่านี้ อย่างไรก็ตามหากคุณต้องการฟังก์ชั่นบางอย่างที่ไม่สามารถใช้โดยตรงหรือแม้กระทั่งโมดูลที่ไม่สามารถนำไปใช้ได้เลยคุณสามารถแนะนำความสำเร็จดังกล่าวจากไลบรารี C/C ++ ได้หรือไม่? คำตอบคือใช่ สิ่งที่คุณต้องทำคือเขียนปลั๊กอินและใช้ทรัพยากรฐานรหัสอื่น ๆ ในรหัส JavaScript ของคุณ มาเริ่มการสอบถามวันนี้ด้วยกัน
แนะนำ
ดังที่ Node.js กล่าวไว้ในเอกสารอย่างเป็นทางการปลั๊กอินเป็นวัตถุที่ใช้ร่วมกันซึ่งเชื่อมโยงแบบไดนามิกซึ่งสามารถเชื่อมต่อรหัส JavaScript กับไลบรารี C/C ++ ซึ่งหมายความว่าเราสามารถอ้างอิงอะไรก็ได้จากไลบรารี C/C ++ และรวมไว้ใน node.js โดยการสร้างปลั๊กอิน
ตัวอย่างเช่นเราจะสร้างการห่อหุ้มสำหรับวัตถุ String String มาตรฐานมาตรฐาน
การตระเตรียม
ก่อนที่เราจะเริ่มเขียนเราต้องตรวจสอบให้แน่ใจว่าเราได้เตรียมวัสดุทั้งหมดที่จำเป็นสำหรับการรวบรวมโมดูลที่ตามมา ทุกคนต้องการ Node-gyp และการพึ่งพาทั้งหมด คุณสามารถใช้คำสั่งต่อไปนี้เพื่อติดตั้ง Node-Gyp:
npm ติดตั้ง -g node -gyp
ในแง่ของการพึ่งพาเราจำเป็นต้องเตรียมโครงการต่อไปนี้สำหรับระบบ UNIX: • Python (ต้องใช้เวอร์ชัน 2.7, 3.x ไม่สามารถทำงานได้อย่างถูกต้อง)
• ทำ
•เครื่องมือคอมไพเลอร์ C ++ (เช่น GPP หรือ G ++)
ตัวอย่างเช่นบน Ubuntu คุณสามารถใช้คำสั่งต่อไปนี้เพื่อติดตั้งโครงการข้างต้นทั้งหมด (Python 2.7 ควรได้รับการติดตั้งล่วงหน้า):
sudo apt-get ติดตั้ง build-essentials
ในสภาพแวดล้อมระบบ Windows สิ่งที่คุณต้องการคือ:
• Python (เวอร์ชัน 2.7.3, 3.x ไม่สามารถทำงานได้ตามปกติ)
• Microsoft Visual Studio C ++ 2010 (สำหรับ Windows XP/Vista)
• Microsoft Visual Studio C ++ 2012 สำหรับ Windows Desktop (สำหรับ Windows 7/8)
เพื่อเน้นย้ำเวอร์ชัน Express ของ Visual Studio สามารถทำงานได้ตามปกติ
ไฟล์ gyp.gyp
ไฟล์นี้ใช้โดย Node-Gyp และได้รับการออกแบบมาเพื่อสร้างไฟล์บิลด์ที่เหมาะสมสำหรับปลั๊กอินของเรา คุณสามารถคลิกที่นี่เพื่อดูเอกสารคำอธิบายไฟล์. gyp ที่จัดทำโดย Wikipedia แต่ตัวอย่างที่เราต้องการใช้ในวันนี้นั้นง่ายมากดังนั้นคุณเพียงแค่ต้องใช้รหัสต่อไปนี้:
{"เป้าหมาย": [{"target_name": "stdstring", "แหล่งที่มา": ["addon.cc", "stdstring.cc"]}]}โดยที่ target_name สามารถตั้งค่าเป็นสิ่งที่คุณต้องการ อาร์เรย์แหล่งที่มามีไฟล์ต้นฉบับทั้งหมดที่ปลั๊กอินต้องการใช้ ในตัวอย่างของเรา Addon.cc รวมอยู่ด้วยซึ่งใช้เพื่อรองรับรหัสที่จำเป็นในการรวบรวมปลั๊กอินและ stdstring.cc รวมถึงคลาส encapsulation ของเรา
คลาส stdstringwrapper
ขั้นตอนแรกคือการกำหนดคลาสของเราเองในไฟล์ stdstring.h หากคุณคุ้นเคยกับการเขียนโปรแกรม C ++ คุณจะไม่คุ้นเคยกับรหัสสองบรรทัดต่อไปนี้
#ifndef stdstring_h #define stdstring_h
สิ่งนี้เป็นของมาตรฐานรวมถึงยาม ต่อไปเราต้องรวมส่วนหัวสองส่วนต่อไปนี้ในหมวดหมู่รวม:
#รวม
#รวม
คนแรกมุ่งเป้าไปที่คลาส Std :: String ในขณะที่ที่สองรวมถึงการกระทำในเนื้อหาที่เกี่ยวข้องกับโหนดและ V8 ทั้งหมด
หลังจากขั้นตอนนี้เสร็จสิ้นเราสามารถประกาศชั้นเรียนของเรา:
คลาส stdstringwrapper: โหนดสาธารณะ :: objectwrap {
สำหรับทุกคลาสที่เราตั้งใจจะรวมไว้ในปลั๊กอินเราต้องขยายคลาสโหนด :: ObjectWrap คลาส
ตอนนี้เราสามารถเริ่มกำหนดคุณสมบัติส่วนตัวของคลาสนี้:
ส่วนตัว: std :: string* s_; stdstringwrapper ที่ชัดเจน (std :: string s = ""); ~ stdstringwrapper ();
นอกเหนือจากตัวสร้างและฟังก์ชั่นการวิเคราะห์เรายังต้องกำหนดตัวชี้สำหรับสตริง std :: นี่คือแกนกลางของเทคโนโลยีนี้และสามารถใช้เชื่อมต่อฐานรหัส C/C ++ กับโหนด - เรากำหนดตัวชี้ส่วนตัวสำหรับคลาส C/C ++ และจะใช้ตัวชี้นี้เพื่อใช้งานการดำเนินงานในวิธีการทั้งหมดที่ตามมา
ตอนนี้เราประกาศคุณสมบัติคงที่ของคอนสตรัคเตอร์ซึ่งจะให้ฟังก์ชั่นสำหรับคลาสที่เราสร้างใน V8:
Static V8 :: Constructor ถาวร;
เพื่อนที่สนใจสามารถคลิกที่นี่เพื่อดูแผนคำอธิบายเทมเพลตสำหรับรายละเอียดเพิ่มเติม
ตอนนี้เรายังต้องการวิธีการใหม่ซึ่งจะถูกกำหนดให้กับตัวสร้างที่กล่าวถึงข้างต้นและ V8 จะเริ่มต้นคลาสของเรา:
Static V8 :: จัดการใหม่ (const v8 :: อาร์กิวเมนต์ & args);
ฟังก์ชั่นทุกอย่างที่ทำบน V8 ควรปฏิบัติตามข้อกำหนดต่อไปนี้: มันจะยอมรับการอ้างอิงถึง V8 :: อาร์กิวเมนต์วัตถุและส่งคืน V8 :: Handle> V8 :: Value>-นี่คือวิธีที่ V8 จัดการกับ JavaScript ประเภทอ่อนแอเมื่อใช้การเข้ารหัส C ++ ประเภทที่แข็งแกร่ง
หลังจากนี้เราจำเป็นต้องแทรกสองวิธีอื่น ๆ ลงในต้นแบบของวัตถุ:
Static V8 :: Handle Add (const v8 :: อาร์กิวเมนต์ & args); Static V8 :: จัดการกับ ToString (Const V8 :: Ariguments & Args);
โดยที่วิธี ToString () ช่วยให้เราได้รับค่าของ S_ แทนค่าของ [วัตถุวัตถุ] เมื่อใช้กับสตริง JavaScript ปกติ
ในที่สุดเราจะแนะนำวิธีการเริ่มต้น (วิธีนี้จะถูกเรียกโดย V8 และกำหนดให้กับฟังก์ชั่นคอนสตรัคเตอร์) และปิดรวมถึงตัวป้องกัน:
สาธารณะ: ช่องว่างคงที่ init (v8 :: จัดการส่งออก); - #endif
บทบาทของวัตถุการส่งออกในโมดูล JavaScript นั้นเทียบเท่ากับโมดูลการส่งออก
ไฟล์ stdstring.cc ตัวสร้างและฟังก์ชั่นการแยกวิเคราะห์
ตอนนี้สร้างไฟล์ stdstring.cc ก่อนอื่นเราต้องรวมส่วนหัวของเรา:
#รวม "stdstring.h"
ต่อไปนี้กำหนดคุณสมบัติสำหรับตัวสร้าง (เพราะมันเป็นของฟังก์ชั่นคงที่):
v8 :: stdstringwrapper ถาวร :: constructor;
ตัวสร้างนี้ที่ให้บริการคลาสจะกำหนดแอตทริบิวต์ S_:
stdStringWrapper :: stdStringWrapper (std :: string s) {s_ = ใหม่ std :: string (s); -และฟังก์ชั่นการแยกวิเคราะห์จะลบออกเพื่อหลีกเลี่ยงหน่วยความจำล้น:
stdstringwrapper :: ~ stdstringwrapper () {ลบ s_; -นอกจากนี้คุณต้องลบเนื้อหาทั้งหมดที่กำหนดด้วยใหม่เนื่องจากทุกครั้งที่สถานการณ์ดังกล่าวอาจทำให้เกิดข้อยกเว้นโปรดจดจำการดำเนินการข้างต้นหรือใช้ตัวชี้ที่ใช้ร่วมกัน
วิธีการเริ่มต้น
วิธีนี้จะถูกเรียกโดย V8 และมีจุดประสงค์เพื่อเริ่มต้นคลาสของเรา (กำหนดตัวสร้างและวางเนื้อหาทั้งหมดที่เราตั้งใจจะใช้ใน JavaScript ในวัตถุส่งออก):
เป็นโมฆะ stdstringWrapper :: init (v8 :: จัดการส่งออก) {
ก่อนอื่นเราต้องสร้างเทมเพลตฟังก์ชันสำหรับวิธีการใหม่ของเรา:
V8 :: tpl local = v8 :: functionTemplate :: ใหม่ (ใหม่);
นี่เป็นเรื่องที่คล้ายกับฟังก์ชั่นใหม่ใน JavaScript - ช่วยให้เราสามารถเตรียมคลาส JavaScript ของเราเอง
ตอนนี้เราสามารถตั้งชื่อสำหรับฟังก์ชั่นตามความต้องการที่แท้จริง (ถ้าคุณพลาดขั้นตอนนี้ตัวสร้างจะอยู่ในสถานะที่ไม่ระบุชื่อนั่นคือชื่อคือฟังก์ชัน somename () {} หรือฟังก์ชั่น () {}):
tpl-> setclassName (v8 :: string :: newsymbol ("stdstring"));
เราใช้ v8 :: string :: newsymbol () เพื่อสร้างสตริงประเภทพิเศษสำหรับชื่อคุณสมบัติ - ซึ่งช่วยประหยัดเวลาเล็กน้อยสำหรับการทำงานของเครื่องยนต์
หลังจากนี้เราจำเป็นต้องตั้งค่าจำนวนฟิลด์อินสแตนซ์คลาสของเราที่มี:
tpl-> instancetemplate ()-> setinternalfieldCount (2);
เรามีสองวิธี - เพิ่ม () และ toString () ดังนั้นเราจึงตั้งค่าเป็น 2 ตอนนี้เราสามารถเพิ่มวิธีการของเราเองลงในต้นแบบฟังก์ชัน:
tpl-> prototypetemplate ()-> set (v8 :: string :: newsymbol ("เพิ่ม"), v8 :: functiontemplate :: ใหม่ (เพิ่ม)-> getFunction ());
tpl-> prototypetemplate ()-> set (v8 :: string :: newsymbol ("toString"), v8 :: functionTemplate :: ใหม่ (toString)-> getFunction ());
ส่วนหนึ่งของรหัสนี้ดูค่อนข้างใหญ่ แต่ตราบใดที่คุณสังเกตอย่างรอบคอบคุณจะพบกฎ: เราใช้ tpl-> rototypetemplate ()-> set () เพื่อเพิ่มแต่ละวิธี นอกจากนี้เรายังใช้ v8 :: string :: newsymbol () เพื่อให้พวกเขามีชื่อและ functiontemplate
ในที่สุดเราสามารถวางตัวสร้างในวัตถุส่งออกภายในคุณสมบัติคลาสคอนสตรัคเตอร์ของเรา:
constructor = v8 :: stervantent :: new (tpl-> getFunction ()); Exports-> set (v8 :: string :: newsymbol ("stdstring"), constructor); -วิธีใหม่
ตอนนี้สิ่งที่เราต้องทำคือกำหนดวิธีที่ทำงานเหมือนกับ JavaScript Object.prototype.constructor:
v8 :: จัดการ stdstringwrapper :: ใหม่ (const v8 :: อาร์กิวเมนต์ & args) {ก่อนอื่นเราต้องสร้างขอบเขตสำหรับมัน:
V8 :: ขอบเขต Handlescope;
หลังจากนี้เราสามารถใช้. isconstructcall () วิธีการของวัตถุ args เพื่อตรวจสอบว่าตัวสร้างสามารถเรียกใช้โดยใช้คำหลักใหม่:
if (args.isconstructcall ()) {หากคุณทำได้เราจะส่งพารามิเตอร์ไปยัง std :: string เป็นครั้งแรก:
v8 :: string :: utf8value str (args [0]-> toString ()); std :: string s (*str);
... ดังนั้นเราจึงสามารถส่งผ่านไปยังตัวสร้างของคลาสที่ห่อหุ้มของเรา:
stdstringWrapper* obj = ใหม่ stdstringWrapper (s);
หลังจากนี้เราสามารถใช้วิธี. wrap () ของวัตถุที่เราสร้างขึ้นก่อนหน้านี้ (สืบทอดมาจาก Node :: ObjectWrap) เพื่อกำหนดให้กับตัวแปรนี้:
obj-> wrap (args.this ());
ในที่สุดเราสามารถส่งคืนวัตถุที่สร้างขึ้นใหม่นี้:
return args.this ();
หากฟังก์ชั่นไม่สามารถเรียกได้ด้วยใหม่เรายังสามารถเรียกตัวสร้างโดยตรง ต่อไปสิ่งที่เราต้องการทำคือตั้งค่าคงที่สำหรับจำนวนพารามิเตอร์:
} else {const int argc = 1;ตอนนี้เราต้องสร้างอาร์เรย์โดยใช้พารามิเตอร์ของเราเอง:
v8 :: local argv [argc] = {args [0]};จากนั้นส่งผ่านผลลัพธ์ของวิธีการสร้าง -> newinstance ไปยังขอบเขตการปิดเพื่อให้วัตถุสามารถมีบทบาทในภายหลัง (ขอบเขตโดยทั่วไปจะช่วยให้ทุกคนรักษามันโดยการย้ายที่จับการประมวลผลวัตถุไปยังช่วงที่สูงขึ้น - นี่คือวิธีการทำงาน):
return scope.close (constructor-> newinstance (argc, argv)); -
เพิ่มวิธีการ
ตอนนี้เรามาสร้างวิธีการเพิ่มซึ่งมีวัตถุประสงค์เพื่อให้ทุกคนสามารถเพิ่มเนื้อหาลงในสตริง std :: string ของวัตถุ:
v8 :: จัดการ stdstringwrapper :: add (const v8 :: อาร์กิวเมนต์ & args) {ก่อนอื่นเราจำเป็นต้องสร้างช่วงสำหรับฟังก์ชั่นของเราและแปลงพารามิเตอร์เป็นสตริง std :: string ก่อน:
V8 :: ขอบเขต Handlescope; v8 :: string :: utf8value str (args [0]-> toString ()); std :: string s (*str);
ตอนนี้เราต้องแกะวัตถุออก นอกจากนี้เรายังได้ดำเนินการ encapsulation encapsulation นี้มาก่อน - คราวนี้เราจะได้รับตัวชี้ไปยังวัตถุจากตัวแปรนี้
stdstringWrapper* obj = objectWrap :: unwrap (args.this ());
จากนั้นเราสามารถเข้าถึงแอตทริบิวต์ S_ และใช้วิธี. Append ():
obj-> s _-> ผนวก (s);
ในที่สุดเราส่งคืนค่าปัจจุบันของแอตทริบิวต์ S_ (จำเป็นต้องใช้ scope.cope อีกครั้ง):
return scope.close (v8 :: string :: new (obj-> s _-> c_str ()));
เนื่องจากวิธี V8 :: String :: ใหม่ () สามารถยอมรับตัวชี้ถ่านเป็นค่าได้เราจำเป็นต้องใช้ obj-> s _-> c_str () เพื่อรับ
ในเวลานี้ควรสร้างไดเรกทอรีบิลด์ในโฟลเดอร์ปลั๊กอินของคุณ
ทดสอบ
ตอนนี้เราสามารถทดสอบปลั๊กอินของเรา สร้างไฟล์ test.js และไลบรารีการรวบรวมที่จำเป็นในไดเรกทอรีปลั๊กอินของเรา (คุณสามารถข้ามส่วนขยาย. node ได้โดยตรง):
var addon = ต้องการ ('./ build/release/addon');ถัดไปสร้างอินสแตนซ์ใหม่สำหรับวัตถุของเรา:
var test = new addon.stdstring ('ทดสอบ');ถัดไปทำเช่นการเพิ่มหรือแปลงเป็นสตริง:
test.add ('!'); console.log ('test/' s เนื้อหา: %s ', การทดสอบ);หลังจากทำงานแล้วคุณควรเห็นผลการดำเนินการต่อไปนี้ในคอนโซล:
สรุปแล้ว
ฉันหวังว่าหลังจากอ่านบทช่วยสอนนี้คุณสามารถขจัดข้อกังวลของคุณและคำนึงถึงการสร้างและทดสอบปลั๊กอิน Node.js ที่กำหนดเองตามไลบรารี C/C ++ เป็นงานที่ยากมาก คุณสามารถใช้เทคโนโลยีนี้เพื่อแนะนำไลบรารี C/C ++ เกือบทุกชนิดใน Node.Js หากคุณต้องการคุณสามารถเพิ่มฟังก์ชั่นเพิ่มเติมลงในปลั๊กอินตามความต้องการที่แท้จริง Std :: String มีวิธีการมากมายและเราสามารถใช้เป็นวัสดุออกกำลังกาย
ลิงค์ปฏิบัติ
เพื่อนที่สนใจสามารถตรวจสอบลิงค์ต่อไปนี้สำหรับทรัพยากรเพิ่มเติมและรายละเอียดที่เกี่ยวข้องกับการพัฒนาปลั๊กอิน Node.js, ไลบรารีลูปเหตุการณ์ V8 และ C
•เอกสารปลั๊กอิน node.js
•เอกสาร V8
• Libuv (C Event Loop Library) จาก GitHub
ภาษาอังกฤษ: http://code.tutsplus.com/tutorials/writing-nodejs-addons--cms-21771