這篇文章主要講解了“nodejs源碼分析中c++層的通用邏輯是什么”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“nodejs源碼分析中c++層的通用邏輯是什么”吧!
在肅南裕固族自治等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì) 網(wǎng)站設(shè)計(jì)制作定制設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),成都全網(wǎng)營(yíng)銷推廣,外貿(mào)網(wǎng)站制作,肅南裕固族自治網(wǎng)站建設(shè)費(fèi)用合理。
我們知道nodejs分為js、c++、c三層,本文以tcp_wrap.cc為例子分析c++層實(shí)現(xiàn)的一些通用邏輯。nodejs的js和c++通信原理q.com/s?__biz=MzUyNDE2OTAwNw==&mid=2247484815&idx=1&sn=525d9909c35eabf3c728b303d27061df&chksm=fa303fcfcd47b6d9604298d0996414a5e16c798c1a2dab4e01989bb41ba9c5372ebc00ca0943&token=162783191&lang=zh_CN#rd)之前已經(jīng)分析過,所以直接從tcp模塊導(dǎo)出的功能開始分析(Initialize函數(shù))。
void TCPWrap::Initialize(Local
這里只摘取了部分的代碼 ,因?yàn)槲覀冎魂P(guān)注原理,這里分別涉及到函數(shù)模板對(duì)象模板和函數(shù)原型等內(nèi)容。上面的代碼以js來表示如下:
function TCP() {
this.reading = false;
// 對(duì)應(yīng)SetInternalFieldCount(1)
this.point = null;
// 對(duì)應(yīng)env->NewFunctionTemplate(New);
New({
Holder: this,
This: this,
returnValue: {},
...
});
}
TCP.prototype.bind = Bind;
TCP.prototype.connect = Connect;
通過上面的定義,完成了c++模塊功能的導(dǎo)出,借助nodejs的機(jī)制,我們就可以在js層調(diào)用TCP函數(shù)。
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const instance = new TCP(...);
instance.bind(...);
我們先分析執(zhí)行new TCP()的邏輯,然后再分析bind的邏輯,因?yàn)檫@兩個(gè)邏輯涉及的機(jī)制是其他c++模塊也會(huì)使用到的。因?yàn)門CP對(duì)應(yīng)的函數(shù)是Initialize函數(shù)里的t->GetFunction()對(duì)應(yīng)的值。所以new TCP()的時(shí)候,v8首先會(huì)創(chuàng)建一個(gè)c++對(duì)象(內(nèi)容由Initialize函數(shù)里定義的那些,也就是文章開頭的那段代碼的定義)。然后執(zhí)行回調(diào)New函數(shù)。
// 執(zhí)行new TCP時(shí)執(zhí)行
void TCPWrap::New(const FunctionCallbackInfo& args) {
// 是否以構(gòu)造函數(shù)的方式執(zhí)行,即new TCP
CHECK(args.IsConstructCall());
CHECK(args[0]->IsInt32());
Environment* env = Environment::GetCurrent(args);
// 忽略一些不重要的邏輯
/*
args.This()為v8提供的一個(gè)c++對(duì)象(由Initialize函數(shù)定義的模塊創(chuàng)建的)
調(diào)用該c++對(duì)象的SetAlignedPointerInInternalField(0,this)關(guān)聯(lián)this(new TCPWrap()),
見HandleWrap
*/
new TCPWrap(env, args.This(), provider);
}
我們看到New函數(shù)的邏輯很簡(jiǎn)單。直接調(diào)用new TCPWrap,其中第二個(gè)入?yún)rgs.This()就是由Initialize函數(shù)定義的函數(shù)模板創(chuàng)建出來的對(duì)象。我們繼續(xù)看new TCPWrap()。
TCPWrap::TCPWrap(Environment* env,
Local
構(gòu)造函數(shù)只有一句代碼,該代碼是初始化一個(gè)結(jié)構(gòu)體,我們可以不關(guān)注,我們需要關(guān)注的是父類ConnectionWrap的邏輯。
template
ConnectionWrap::ConnectionWrap(Environment* env,
Local
我們發(fā)現(xiàn)ConnectionWrap也沒有什么邏輯,繼續(xù)看LibuvStreamWrap。
LibuvStreamWrap::LibuvStreamWrap(Environment* env,
Local
繼續(xù)做一些初始化,我們只關(guān)注HandleWrap
HandleWrap::HandleWrap(Environment* env,
Local
重點(diǎn)來了,就是Wrap函數(shù)。
template
void Wrap(v8::Local object, TypeName* pointer) {
object->SetAlignedPointerInInternalField(0, pointer);
}
void v8::Object::SetAlignedPointerInInternalField(int index, void* value) {
i::Handle obj = Utils::OpenHandle(this);
i::Handle::cast(obj)->SetEmbedderField(
index, EncodeAlignedAsSmi(value, location));
}
void JSObject::SetEmbedderField(int index, Smi* value) {
// GetHeaderSize為對(duì)象固定布局的大小,kPointerSize * index為拓展的內(nèi)存大小,根據(jù)索引找到對(duì)應(yīng)位置
int offset = GetHeaderSize() + (kPointerSize * index);
// 寫對(duì)應(yīng)位置的內(nèi)存,即保存對(duì)應(yīng)的內(nèi)容到內(nèi)存
WRITE_FIELD(this, offset, value);
}
Wrap函數(shù)展開后,做的事情就是把一個(gè)值保存到v8 c++對(duì)象的內(nèi)存里。那保存的這個(gè)值是啥呢?我們看Wrap函數(shù)的入?yún)rap(object, this)。object是由函數(shù)模板創(chuàng)建的對(duì)象,this是一個(gè)TCPWrap對(duì)象。所以Wrap函數(shù)做的事情就是把一個(gè)TCPWrap對(duì)象保存到一個(gè)函數(shù)模板創(chuàng)建的對(duì)象里。這有啥用呢?我們繼續(xù)分析。這時(shí)候new TCP就執(zhí)行完畢了。我們看看這時(shí)候執(zhí)行new TCP().bind()函數(shù)的邏輯。
void TCPWrap::Bind(const FunctionCallbackInfo& args) {
TCPWrap* wrap;
// 解包處理
ASSIGN_OR_RETURN_UNWRAP(&wrap,
args.Holder(),
args.GetReturnValue().Set(UV_EBADF));
node::Utf8Value ip_address(args.GetIsolate(), args[0]);
int port = args[1]->Int32Value();
sockaddr_in addr;
int err = uv_ip4_addr(*ip_address, port, &addr);
if (err == 0) {
err = uv_tcp_bind(&wrap->handle_,
reinterpret_cast(&addr),
0);
}
args.GetReturnValue().Set(err);
}
我們只需關(guān)系A(chǔ)SSIGN_OR_RETURN_UNWRAP宏的邏輯。其中args.Holder()表示Bind函數(shù)的屬主,根據(jù)前面的分析我們知道屬主是Initialize函數(shù)定義的函數(shù)模板創(chuàng)建出來的對(duì)象。這個(gè)對(duì)象保存了一個(gè)TCPWrap對(duì)象。我們展開ASSIGN_OR_RETURN_UNWRAP看看。
#define ASSIGN_OR_RETURN_UNWRAP(ptr, obj, ...) \
do { \
*ptr = \
Unwrap::type>(obj); \
if (*ptr == nullptr) \
return __VA_ARGS__; \
} while (0)
template
TypeName* Unwrap(v8::Local object) {
// 把調(diào)用SetAlignedPointerFromInternalField設(shè)置的值取出來
void* pointer = object->GetAlignedPointerFromInternalField(0);
return static_cast(pointer);
}
展開后我們看到,主要的邏輯是把在c++對(duì)象中保存的那個(gè)TCPWrap對(duì)象取出來。然后就可以使用TCPWrap對(duì)象了。
感謝各位的閱讀,以上就是“nodejs源碼分析中c++層的通用邏輯是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)nodejs源碼分析中c++層的通用邏輯是什么這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!