Node.js имеет наилучший эффект в написании бэкэндов с использованием JavaScript, и это стоит попробовать больше. Однако, если вам нужны некоторые функции, которые нельзя использовать напрямую или даже модули, которые вообще не могут быть реализованы, можете ли вы представить такие достижения из библиотеки C/C ++? Ответ да. Все, что вам нужно сделать, это написать плагин и использовать другие базовые ресурсы кода в коде JavaScript. Давайте начнем сегодняшнее расследование вместе.
представлять
Как говорится в официальной документации Node.js, плагины являются общими объектами, которые связаны динамически, которые могут подключать код JavaScript с библиотеками C/C ++. Это означает, что мы можем ссылаться на что угодно из библиотеки C/C ++ и включить его в node.js, создав плагины.
В качестве примера мы создадим инкапсуляцию для стандартного объекта Std :: String.
Подготовка
Прежде чем мы начнем писать, мы должны убедиться, что мы подготовили все материалы, необходимые для последующей компиляции модуля. Каждому нужны узлы-гип и все зависимости. Вы можете использовать следующую команду для установки Node-GYP:
npm install -g node -gyp
Что касается зависимостей, нам необходимо подготовить следующие проекты для систем UNIX: • Python (требует версии 2.7, 3.x не может работать должным образом)
• делать
• Компилятор C ++ (например, GPP или G ++)
Например, на Ubuntu вы можете использовать следующую команду для установки всех вышеперечисленных проектов (Python 2.7 должен был быть предварительно установлен):
Sudo apt-get установить сборки
В системной среде Windows вам нужно:
• Python (версия 2.7.3, 3.x не может работать нормально)
• Microsoft Visual Studio C ++ 2010 (для Windows XP/Vista)
• Microsoft Visual Studio C ++ 2012 для рабочего стола Windows (для Windows 7/8)
Чтобы подчеркнуть, экспресс -версия Visual Studio также может работать нормально.
file binding.gyp
Этот файл используется Node-GYP и предназначен для создания соответствующего файла сборки для нашего плагина. Вы можете щелкнуть здесь, чтобы просмотреть документ .gyp файла Описания, предоставленного Wikipedia, но пример, который мы хотим использовать сегодня, очень прост, поэтому вам просто нужно использовать следующий код:
{"Targets": [{"target_name": "stdString", "источники": ["addon.cc", "stdstring.cc"]}]}где target_name может быть установлен на все, что вам нравится. Массив источников содержит все исходные файлы, которые необходимо использовать плагин. В нашем примере также включен addon.cc, который используется для размещения кода, необходимого для компиляции плагинов и stdstring.cc, а также наш класс инкапсуляции.
StdstringWrapper Class
Первым шагом является определение нашего собственного класса в файле stdstring.h. Если вы знакомы с программированием C ++, вы определенно не будете незнакомы со следующими двумя строками кода.
#ifndef stdstring_h #define stdstring_h
Это принадлежит стандарту, включайте охрану. Далее нам нужно включить следующие два заголовка в категорию «Включить»:
#включать
#включать
Первый предназначен для класса Std :: String, а второй включает в себя действия на всех узлах и V8.
После завершения этого шага мы можем объявить наш класс:
класс stdstringwrapper: public node :: objectWrap {
Для всех классов мы намерены включить в плагин, мы должны расширить класс Node :: ObjectWrap.
Теперь мы можем начать определять частную собственность этого класса:
private: std :: string* s_; явный stdstringwrapper (std :: string s = ""); ~ StdstringWrapper ();
В дополнение к конструкторам и аналитическим функциям, нам также необходимо определить указатель для std :: string. Это является ядром этой технологии и может использоваться для подключения базы кода C/C ++ к узлу - мы определяем личный указатель для класса C/C ++ и будем использовать этот указатель для реализации операций во всех последующих методах.
Теперь мы объявляем статическое свойство конструктора, которое предоставит функции для класса, который мы создали в V8:
Статический V8 :: постоянный конструктор;
Заинтересованные друзья могут нажать здесь, чтобы обратиться к плану описания шаблона для получения более подробной информации.
Теперь нам также нужен новый метод, который будет назначен конструктору, упомянутому выше, и V8 инициализирует наш класс:
static v8 :: обрабатывает новый (const v8 :: аргументы & args);
Каждая функция, действующая на V8, должна следовать следующим требованиям: она примет ссылки на объекты V8 :: Arguments и вернуть v8 :: handle> v8 :: value>-Это именно то, как V8 имеет дело со JavaScript слабая типа при использовании кодирования C ++ сильного типа.
После этого нам нужно вставить два других метода в прототип объекта:
static v8 :: add add (const v8 :: arguments & args); static v8 :: handle tostring (const v8 :: аргументы & args);
где метод toString () позволяет нам получить значение S_ вместо значения [объекта объекта] при его использовании с обычной строкой JavaScript.
Наконец, мы введем метод инициализации (этот метод будет вызван V8 и назначен функции конструктора) и закрыть включать Guard:
public: static void init (v8 :: handle exports); }; #endif
Роль объекта Exports в модуле JavaScript эквивалентна Module.exports.
Функция, конструктор и анализ файла stdstring.cc
Теперь создайте файл stdstring.cc. Сначала нам нужно включить наш заголовок:
#include "stdstring.h"
Следующее определяет свойство для конструктора (потому что оно принадлежит статической функции):
v8 :: постоянная stdstringwrapper :: constructor;
Этот конструктор, обслуживающий класс, назначит атрибут S_:
Stdstringwrapper :: stdstringwrapper (std :: string s) {s_ = new std :: string (s); }И функция анализа удалит его, чтобы избежать переполнения памяти:
Stdstringwrapper :: ~ stdstringwrapper () {delete s_; }Кроме того, вы должны удалить весь контент, назначенный новым, потому что каждый раз, когда такая ситуация может вызывать исключение, помните вышеуказанные операции или использовать общий указатель.
Инициальный метод
Этот метод будет вызван V8 и предназначен для инициализации нашего класса (назначить конструктор и поместить весь контент, который мы намерены использовать в JavaScript в объекте Exports):
void stdstringwrapper :: init (v8 :: handle exports) {
Во -первых, нам нужно создать шаблон функций для нашего нового метода:
v8 :: local tpl = v8 :: functiontemplate :: new (new);
Это немного похоже на новую функцию в JavaScript - это позволяет нам подготовить наши собственные классы JavaScript.
Теперь мы можем установить имя для функции в соответствии с фактическими потребностями (если вы пропустите этот шаг, конструктор будет в анонимном состоянии, то есть имя - функция somename () {} или function () {}):
tpl-> setclassname (v8 :: string :: newsymbol ("stdstring"));
Мы используем v8 :: string :: newsymbol () для создания строки специального типа для названий свойств - что сохраняет немного времени для работы двигателя.
После этого нам нужно установить, сколько полей содержит наш экземпляр класса:
tpl-> instancetemplate ()-> setInternalfieldCount (2);
У нас есть два метода - add () и toString (), поэтому мы устанавливаем число на 2. Теперь мы можем добавить наши собственные методы к прототипу функции:
tpl-> prototypletemplate ()-> set (v8 :: string :: newsymbol ("add"), v8 :: functiontemplate :: new (add)-> getFunction ());
tpl-> prototypetTemplate ()-> set (v8 :: string :: newsymbol ("toString"), v8 :: functiontemplate :: new (toString)-> getFunction ());
Эта часть кода выглядит довольно большой, но пока вы тщательно наблюдаете, вы найдете правила: мы используем TPL-> PrototyTemplate ()-> set () для добавления каждого метода. Мы также используем v8 :: string :: newsymbol (), чтобы предоставить им имена и функционально.
Наконец, мы можем поместить конструктор в объект Exports в свойствах нашего класса конструктора:
constructor = v8 :: repistent :: new (tpl-> getFunction ()); Exports-> set (v8 :: string :: newsymbol ("stdstring"), конструктор); }Новый метод
Теперь мы должны определить метод, который работает так же, как javascript object.prototype.constructor:
v8 :: handle stdstringwrapper :: new (const v8 :: arguments & args) {Сначала нам нужно создать сферу для этого:
V8 :: HandleCope Scope;
После этого мы можем использовать метод .isconstructcall () объекта Args, чтобы проверить, можно ли вызвать конструктор с помощью нового ключевого слова:
if (args.isconstructcall ()) {Если вы можете, сначала мы передаем параметр std :: string следующим образом:
v8 :: string :: utf8value str (args [0]-> toString ()); std :: string s (*str);
... чтобы мы могли передать его в конструктор нашего инкапсулированного класса:
Stdstringwrapper* obj = new StdstringWrapper (ы);
После этого мы можем использовать метод .wrap () объекта, который мы создали ранее (унаследовали от Node :: ObjectWrap), чтобы назначить его этой переменной:
obj-> wrap (args. this ());
Наконец, мы можем вернуть этот недавно созданный объект:
вернуть args.this ();
Если функция не может быть вызвана с новой, мы также можем вызвать конструктор напрямую. Далее, что мы хотим сделать, это установить константу для количества параметров:
} else {const int argc = 1;Теперь нам нужно создать массив, используя наши собственные параметры:
v8 :: local argv [argc] = {args [0]};Затем передайте результат метода конструктора-> newInstance в области объема.
return scope.close (конструктор-> newinstance (argc, argv)); }}
добавить метод
Теперь давайте создадим метод добавления, который предназначен для того, чтобы позволить каждому добавлять контент во внутреннюю std :: string ::
v8 :: handle stdstringwrapper :: add (const v8 :: arguments & args) {Во -первых, нам нужно создать диапазон для нашей функции и преобразовать параметр в std :: string, как и раньше:
V8 :: HandleCope Scope; v8 :: string :: utf8value str (args [0]-> toString ()); std :: string s (*str);
Теперь нам нужно распаковать объект. Мы также выполняли эту операцию обратной инкапсуляции раньше - на этот раз мы собираемся получить указатель на объект из этой переменной.
StdstringWrapper* obj = ObjectWrap :: unwrap (args.tis ());
Затем мы можем получить доступ к атрибуту S_ и использовать его метод .append ():
obj-> s _-> Приложение (s);
Наконец, мы возвращаем текущее значение атрибута S_ (необходимо использовать Scope.close снова):
return scope.close (v8 :: string :: new (obj-> s _-> c_str ()));
Поскольку метод v8 :: string :: new () может принять указатель HAR только в качестве значения, нам нужно использовать obj-> s _-> c_str (), чтобы получить его.
В настоящее время в вашей папке плагина должен быть создан каталог сборки.
тест
Теперь мы можем проверить наши плагины. Создайте файл test.js и необходимые библиотеки компиляции в нашем каталоге плагинов (вы можете напрямую пропустить расширение .node):
var addon = require ('./ build/release/addon');Далее создайте новый экземпляр для нашего объекта:
var test = new addon.stdstring ('test');Далее сделайте это, например, добавление или преобразование в строку:
test.add ('!'); console.log ('test/' s Содержимое: %s ', test);После запуска вы должны увидеть следующие результаты выполнения в консоли:
в заключение
Я надеюсь, что после прочтения этого учебника вы можете развеять свои проблемы и рассматривать создание и тестирование плагинов 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