Nodejs的运行原理-函数回调篇详解编程语言

前言

当客户端向http server 发起TCP链接时,server端会发起一系列的callback调用,这是一个逆向调用的过程;开始于libuv,终止于js代码里的callback(promise then)函数。

如下图所示,http server 正向调用过程,实际大部分的时间花在net.js上,直到最下面的红框,才调用了关键函数createTCP()

function createTCP() { 
   //绑定tcp_wrap模块,调用tcp constructor。    
    var TCP = process.binding('tcp_wrap').TCP; 
    return new TCP(); 
} 

 

 Nodejs的运行原理-函数回调篇详解编程语言

tcp_wrap模块

我们看一下tcpwrap::initialize()的代码:

          void TCPWrap::Initialize(Handle<Object> target, Handle<Value> unused, Handle<Context> context) { 
	  Environment* env = Environment::GetCurrent(context); 
	 
	  Local<FunctionTemplate> t = FunctionTemplate::New(env->isolate(), New); 
	  t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TCP")); 
	  t->InstanceTemplate()->SetInternalFieldCount(1); 
	  // Init properties 
	  t->InstanceTemplate()->Set(String::NewFromUtf8(env->isolate(), "reading"),Boolean::New(env->isolate(), false)); 
	  t->InstanceTemplate()->Set(String::NewFromUtf8(env->isolate(), "owner"),Null(env->isolate())); 
	  t->InstanceTemplate()->Set(String::NewFromUtf8(env->isolate(), "onread"),Null(env->isolate())); 
	  t->InstanceTemplate()->Set(String::NewFromUtf8(env->isolate(),"onconnection"),Null(env->isolate())); 
	 
	  NODE_SET_PROTOTYPE_METHOD(t, "open", Open); 
	  NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind); 
	  NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen); 
	  NODE_SET_PROTOTYPE_METHOD(t, "getsockname", GetSockName); 
	 
	  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TCP"), t->GetFunction()); 
	  } 
	 
	NODE_MODULE_CONTEXT_AWARE_BUILTIN(tcp_wrap, node::TCPWrap::Initialize) 

 利用v8 engine的 functionTemplate 创建一个js类。

类的constructor 是 TCP(),

类的prototype是NODE_SET_PROTOTYPE_METHOD()

类的属性是t->InstanceTemplate()->Set().

在执行函数createTCP()调用process.binding(‘tcp_wrap’)时,其实会调用到下图。在红框内,可以看到参数target被设置成了export对象,也就是说,tcp_wrap模块真正导出的是TCP函数

Nodejs的运行原理-函数回调篇详解编程语言

Server.prototype._listen2

Nodejs的运行原理-函数回调篇详解编程语言

结合上图,我们可以看到函数_listen2中调用createServerHandle() 返回了一个_handle对象,并且self._handle.onconnection = onconnection,这一步也非常重要。

AsyncWrap准备工作

AsyncWrap 和Env的代码截图:

Nodejs的运行原理-函数回调篇详解编程语言

准备工作及流程:

Nodejs的运行原理-函数回调篇详解编程语言

callBack的逆向调用

前面都是铺垫,这里才是正题。

正向调用过程,从createServer()开始,到listen()结束,为了创建一个基于TCP的http server。了解socket流程的都知道,到此为止,创建工作实际已经完成,剩下的就是等待客户connect。

而所有的callback执行的目的是对应用程序构造出一个socket的对象,并且基于此对象完成面向连接的数据流读取操作。

下图为调用流程:

Nodejs的运行原理-函数回调篇详解编程语言

 

First callback

TCP::Listen()通过libuv提供的uv_listen()实现了listen异步调用,并且指定了callback回调函数TCPWrap::OnConnection()。

OnConnection()由libuv的event loop调用。

在看Nodejs Env.h 和 Env-inl.h 中可找到PER_ISOLATE_STRING_PROPERTIES(v)若干引用,就像上面图所示,env->onconnection_string()会返回symbole onconnection

MakeCall中,通过object()->Get()获取symbole的对应函数。

Other callback

net.js中的onconnection()会被调用,如下图所示:

Nodejs的运行原理-函数回调篇详解编程语言

两个要点,一是创建了socket对象,二是发出了connection时间。

开发者调用createServer()时,其实是在执行new Server(),而类Server中对connection之间有一个监听者,那就是connectionListener(),也就是第三个callback。

通过前文,我想后面的事情就不在赘述了。

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/11739.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论