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();
}

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函数。

Server.prototype._listen2

结合上图,我们可以看到函数_listen2中调用createServerHandle() 返回了一个_handle对象,并且self._handle.onconnection = onconnection,这一步也非常重要。
AsyncWrap准备工作
AsyncWrap 和Env的代码截图:

准备工作及流程:

callBack的逆向调用
前面都是铺垫,这里才是正题。
正向调用过程,从createServer()开始,到listen()结束,为了创建一个基于TCP的http server。了解socket流程的都知道,到此为止,创建工作实际已经完成,剩下的就是等待客户connect。
而所有的callback执行的目的是对应用程序构造出一个socket的对象,并且基于此对象完成面向连接的数据流读取操作。
下图为调用流程:

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()会被调用,如下图所示:

两个要点,一是创建了socket对象,二是发出了connection时间。
开发者调用createServer()时,其实是在执行new Server(),而类Server中对connection之间有一个监听者,那就是connectionListener(),也就是第三个callback。
通过前文,我想后面的事情就不在赘述了。
Nodejs的运行原理-函数回调篇的更多相关文章
- Nodejs的运行原理-架构篇
前言 本来是想只做一个Nodejs运行原理-科普篇,但是收到了不少私信,要我多分享一些更进阶,更详细的内容,所以我会在接下来的两个月里继续更新Nodejs运行原理. PS:此系列只做Nodejs的运行 ...
- Nodejs的运行原理-调用篇
前言 之前做过Nodejs的架构篇, 有很多朋友留言给我,说没看懂里面的例子,这里我会重新梳理一下,再以http server为例,来解析Nodejs从前端到libuv的调用过程. 正文 回忆a. N ...
- Nodejs的运行原理-libuv篇
前言 这应该是Nodejs的运行原理的第7篇分享,这篇过后,短时间内不会再分享Nodejs的运行原理,会停更一段时间,PS:不是不更,而是会开挖新的坑,最近有在研究RPG Maker MV,区块链,云 ...
- 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
- Nodejs的运行原理-科普篇
前言 Nodejs目前处境稍显尴尬,很多语言都已经拥有异步非阻塞的能力.阿里的思路是比较合适的,但是必须要注意,绝对不能让node做太多的业务逻辑,他只适合接收生成好的数据,然后或渲染后,或直接发送到 ...
- Nodejs的运行原理-生态篇
前言 这里是重点:Nodejs 是由v8 engine,libuv和内置模块组成,可以将v8 engine和 libuv看成一个库,两者是以源码的方式直接编译执行node中去的. 这是一个广泛的介绍, ...
- Nodejs的运行原理-模块篇
前言 使用Nodejs,就不可避免地引用第三方模块,它们有些是Nodejs自带的(例:http,net...),有些是发布在npm上的(例:mssql,elasticsearch...) 本篇章聚焦3 ...
- Pytorch源码与运行原理浅析--网络篇(一)
前言 申请的专栏开通了,刚好最近闲下来了,就打算开这个坑了hhhhh 第一篇就先讲一讲pytorch的运行机制好了... 记得当时刚刚接触的时候一直搞不明白,为什么自己只是定义了几个网络,就可以完整的 ...
- SpringBoot-02 运行原理初探
SpringBoot-02 运行原理初探 本篇文章根据b站狂神编写 pom.xml 2.1.父依赖 其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件! <parent> < ...
随机推荐
- SpringMVC框架学习笔记——各种异常、报错解决
1.Target runtime com.genuitec.runtime.generic.jee60 is not defined. 找到导入项目的.setting文件夹org.eclipse.ws ...
- 将数据按照gzip当时解压的工具类
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; impo ...
- Vue.js实现一个SPA登录页面的过程
技术栈 vue.js 主框架 vuex 状态管理 vue-router 路由管理 一般过程 在一般的登录过程中,一种前端方案是: 检查状态:进入页面时或者路由变化时检查是否有登录状态(保存在cooki ...
- EntityFramework默认映射规则
我不太习惯通过CodeFirst去维护数据库(尽管这是未来实现自动编程的必经之路),还是喜欢通过数据库设计工具如PowerDesigner去建表.如果不想对EF的实体和数据表做什么映射的话,就要注意默 ...
- VisualSVN Server的配置和使用方法
VisualSVN Server是免费的,而VisualSVN是收费的.VisualSVN是SVN的客户端,和Visual Studio集成在一起, VisualSvn Server是SVN的服务器端 ...
- 一键批量打印EXCEL、WORD文档
一键批量打印EXCEL.WORD文档,本方法也可以打印同一个文档N份,可以批量打印A3.A4文档,包括单.双面打印等.希望能帮到广大朋友.请大家注重原创版权,不得在未经许可的下转载.传播,或者用来对同 ...
- PHP flock() 函数
定义和用法 flock() 函数锁定或释放文件. 若成功,则返回 true.若失败,则返回 false. 语法 flock(file,lock,block) 参数 描述 file 必需.规定要锁定或释 ...
- 微信公众号tp3.2放进Model无效,几种实例化的方法试过,还是提示无法提供服务
http://www.imooc.com/video/10230 解决方案一: $indexModel = D('Index'); 实测可行 解决方案一: 使用TP3.2的小伙伴需要注意了,在Mod ...
- eclipse中git解决冲突
摘录自http://blog.csdn.net/rosten/article/details/17068285 1. 工程->Team->同步 2.从远程pull至本地,就会出现如下内容 ...
- 解决eclipse出现This Android SDK requires Andro...date ADT to the latest version.问题
更新完android SDK之后,eclipse出现了“This Android SDK requires Andro...date ADT to the latest version.”问题,这是因 ...