Using C and C++ to implement node. js module (ii)

  • 2020-03-30 03:59:13
  • OfStack

Review the old and learn the new, can be wet

First, keep in mind the V8 online manual -- http://izs.me/v8-docs/main.html.

Remember the building.gyp file from last time?


{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon.cc" ]
    }
  ]
}

  Just like this, if a few more *.cc files is like this:
Sources: ["addon.cc", "myexample.cc"]

  Last time we separated the two steps, in fact the configuration and compilation can be put together:
$node - gyp configure build

  Have you finished reviewing? Yet? !

Okay, let's move on.

Table's

Function parameters

Now we're finally going to talk about parameters.

Let's imagine that the function add(a, b) returns the result of adding a and b, so let's write the function box first:


#include <node.h>
using namespace v8; Handle<Value> Add(const Arguments& args)
{
    HandleScope scope;     //. Come again! < br / > }

  The Arguments

This is the argument to the function. Let's take a look at the official v8 manual first.
  The & # 8226; Const int Length ()
  The & # 8226; Local< Value> Operator [] (int I) const
 
We don't care about the rest. These two are important! One represents the number of arguments passed into the function, and the other bracket accesses the NTH argument through the index.

So the above requirements, we can roughly understand that args.length () is 2, args[0] for a and args[1] for b. And we have to determine the type of these two Numbers to be Number.

Notice that the index operator in the middle bracket returns a Local< Value> This is the base class for all types of node. js. So the types of arguments that are passed in are variable, and we have to decide for ourselves what they are. This is related to some functions of this Value type.

  The & # 8226; IsArray ()
The & # 8226; IsBoolean ()
The & # 8226; IsDate ()
The & # 8226; IsFunction ()
The & # 8226; IsInt32 ()
The & # 8226; IsNativeError ()
The & # 8226; IsNull ()
The & # 8226; IsNumber ()
The & # 8226; IsRegExp ()
The & # 8226; IsString ()
The & # 8226; .
 
I'm not going to go through the list, but I'm going to go through the rest of the documentation. The & # 65377; : the & # 65439; � (* & acute; The & # 8704; `) & # 65417; The & # 65439; . : the & # 65377;

ThrowException

This is a function that we're going to use in a second. The details can be found in the v8 documentation.

As the name implies, it just throws an error. After executing this statement, it is equivalent to executing a throw() statement in the node.js local file. Such as:
ThrowException (Exception: : TypeError (String: : the New (" Wrong number of arguments ")));

  It is equivalent to executing a node. js:
Throw new TypeError("Wrong number of arguments");

  Undefined ()

This function is also in the document.

It's just going to be a null value, because some functions don't have to return a specific value, or they don't return a value, so you're going to have to replace it with Undefined().

Begin SAO year!

After understanding the above points, I believe that you will soon be able to write the logic of a + b, so I will just copy the code of the official manual of node. js and go through it for you.


#include <node.h>
using namespace v8; Handle<Value> Add(const Arguments& args)
{
    HandleScope scope;     //Represents that more than 2 arguments can be passed in, but in fact we only use the first two
    if(args.Length() < 2)
    {
        //Throws an error
        ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));         //Returns a null value
        return scope.Close(Undefined());
    }     //
if one of the first two arguments is not a number     if(!args[0]->IsNumber() || !args[1]->IsNumber())
    {
        //Throws an error and returns a null value
        ThrowException(Exception::TypeError(String::New("Wrong arguments")));
        return scope.Close(Undefined());
    }     //Refer to the v8 document
for details     //     http://izs.me/v8-docs/classv8_1_1Value.html#a6eac2b07dced58f1761bbfd53bf0e366)
    //'NumberValue' of
    Local<Number> num = Number::New(args[0]->NumberValue() + args[1]->NumberValue());     return scope.Close(num);
}

  The function is done!

And then I'm just going to write down the output function at the end.


void Init(Handle<Object> exports)
{
    exports->Set(String::NewSymbol("add"),
        FunctionTemplate::New(Add)->GetFunction());
} NODE_MODULE(addon, Init)

  After you compile it, you can use it like this:

var addon = require('./build/Release/addon');
console.log(addon.add(1, 1) + "b");

  You'll see a 2b! The & # 10023; The & # 65377; The & # 1641; ( � & # 5596; � ) & # 1608; The & # 10023; * & # 65377;

The callback function

The last chapter we just talked about a Hello world, this chapter on the conscience of the old woman, and then write a callback function.

The convention is to write the framework:


#include <node.h>
using namespace v8; Handle<Value> RunCallback(const Arguments& args)
{
  HandleScope scope;   //. Pitter patter pitter patter   return scope.Close(Undefined());
}   Then we decided that it would be used like this:
func(function(msg) {
    console.log(msg);
});

  That is, it passes in an argument to the callback function, which we assume is a string, and then we can console.log().

First you have to have a series of strings

Without further ado, give it a string to feed. Zeta () epsilon:)

But we have to make this string generic, because the node. js code is weakly typed.
Local< Value> : : the New (String: : the New (" hello world "));

  What? You asked me what is local&lst; Value> ?

So let me talk about it a little bit, refer to here and the V8 reference documentation.

As documented, Local< T> It's actually inherited from Handle< T> I remember we talked about Handle< in the last chapter. T> This thing is gone.

And then there's Local.


There are two types of Handle, Local Handle and Persistent Handle, which are respectively Local< T> : Handle< T> And Persistent< T> : Handle< T> , the former and Handle< T> There is no difference between life cycle in scope. The life cycle of the latter is separated from scope, and you need to manually call Persistent::Dispose to end its life cycle. In other words, Local Handle is equivalent to C++ 'allocating objects on the stack, while Persistent Handle is equivalent to C++ allocating objects on the heap.
 
And then you have a list of parameters

How to take command line arguments after terminal command line calls C/C++?


#include <stdio.h> void main(int argc, char* argv[])
{
    // ...
}

  By the way, argc here is the number of command-line arguments, and argv[] is each argument. Then call the node. js callback function, and v8 takes a similar approach:

V8EXPORT Local<Value> v8::Function::Call(Handle<Object>recv,
    int argc,
    Handle<Value> argv[]
);

  The QAQ card is in hand. Object> Recv!! Continue writing tomorrow. ~ ~
 
Well, a new day begins and I feel empowered. Studying ^ o ^) & # 8835; ━ fostered the & # 65439; . * & # 65381; The & # 65377;

After several tests (SegmentFault and StackOverflow and a QQ group), I finally solved the meaning of three parameters of the above function.

The following two parameters are not said, one is the number of parameters, and the other is an array of parameters. As for the first parameter Handle< Object> Recv StackOverflow's explanation is this:


It is the same as apply in JS. In JS, you do


var context = ...;
cb.apply(context, [ ...args...]);

  The object passed as The first argument becomes this within The function scope. More documentation on MDN. If you don't know JS well, you can read More about JS's this here: http://unschooled.org/2012/03/understanding-javascript-this/).
 
From StackOverflow

All it does is specify the this pointer to the called function. This Call is used similarly to bind(), Call (), and apply() in JavaScript.

So all we need to do is set up the argument list and pass in the Call function for execution.

The first step is to display the conversion function, because it was originally of type Object:
Local< Function> Cb = Local< Function> : : Cast (args [0]);

  Step 2: set up the parameter table (array) :
Local< Value> Argv [arg c] = {Local< Value> : : the New (String: : the New (" hello world ")};

  Finally, the function family is called

Call cb and pass in the parameters:
Cb - > The Call (the Context: : GetCurrent () - > Global (), 1, argv);

  The first argument here is Context::GetCurrent()-> Global() means to get the Global context as a function of this; The second parameter is the number of parameters in the list (after all, although node. js array has a length property, the length of the array in C++ is actually unknown to the system, and you have to pass in a number to specify the length of the array). The last parameter is the parameter list that we just set up.

End of chapter series

I'm sure you're familiar with this step, which is to write the function, put it in the derived function, and then declare it.

I'll just release the code, or I'll just go to the node. js documentation.


#include <node.h>
using namespace v8; Handle<Value> RunCallback(const Arguments& args)
{
    HandleScope scope;
    Local<Function> cb = Local<Function>::Cast(args[0]);
    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) };
    cb->Call(Context::GetCurrent()->Global(), argc, argv);     return scope.Close(Undefined());
} void Init(Handle<Object> exports, Handle<Object> module)
{
    module->Set(String::NewSymbol("exports"),
        FunctionTemplate::New(RunCallback)->GetFunction());
}

NODE_MODULE (addon, Init)

  Well done! The last few steps are on your own. As far as calling this function in Js is concerned, I mentioned it earlier.

One day

Well, I feel like my study notes are getting more and more unrestrained

I'll leave it at that for today, because I got a lot of postures during the process of writing notes, such as the parameter meaning of the Call function.

If you think this series study notes and help to you, come with me and gay mua ~ Σ > ( ° ° ° )♡ -


Related articles: