node源码详解(三)
本作品采用知识共享署名 4.0 国际许可协议进行许可。转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource3 
本博客同步在https://cnodejs.org/topic/56e3dfde545c5c736d12383f 
本博客同步在http://www.cnblogs.com/papertree/p/5225994.html
我们用惯了process.nextTick()、require('xxx')、module.exports,但是它们哪里来呢?下文给出答案...
3.1 node main函数到执行js文件的位置
3.1.1 入口
上篇博客2.1中提到src目录存放的是node的C++源码部分,包括main函数。
src/node_main.cc 和 src/node.cc(注:.cc是linux下的C++文件,类似windows下的.cpp)这两个文件就是node的入口文件。
其中node_main.cc里面仅仅作为一个入口,调用node.cc 文件中的node::Start()。
  
图3-1-1
3.1.2 node::Start()到加载js文件
有兴趣可以看一下node::Start()函数做些什么(代码截图放上来了),我们关注的只是里面的StartNodeInstance()这一行。
  
图3-1-2
我们来看一下一连串的调用:
Start() -> StartNodeInstance() -> LoadEnviroment() -> ExecuteString()
这四个函数都在node.cc文件里面,看到LoadEnviroment() 几行关键代码:
  
图3-1-3
最终在LoadEnvrioment()里面加载node.js文件,调用ExecuteString()。
并且在ExecuteString()调用V8的 Script::Compile() 和 Script::Run()两个接口去解析执行js代码。
3.1.3 node.js文件和用户的app.js文件
通过命令行“node app.js”启动,我们希望node执行的是app.js 文件,为什么LoadEnvironment()里面加载的是node.js文件呢?
上篇博客2.1 讲到node的lib文件夹存放原生js模块,而src文件夹里面全部是.cc文件(node C++源码) ,但src下面有一个node.js文件。这个文件的作用是什么呢?
3.2 node.js文件,包装app.js文件,require/module.exports
先来看node.js文件的结构:
  
图 3-2-1
3.2.1 node.js 返回的是一个函数
看到3.1.2 中,在LoadEnvironment()里面调用ExecuteString() 解析执行node.js文件,返回值是一个f_value。
而这个f_value通过V8的接口 Local<Function>::Cast转换成一个Local<Function>类型的变量f ,而Local<Function>类型是V8中表示一个js 函数的C++类型。
在LoadEnvironment()的最后一行通过 f->Call(),去执行node.js返回来的一个函数。
而从node.js文件中也可以看出确实返回的是一个匿名函数。
所以,我们的app.js并不在ExecuteString()里面执行,而是在f->Call()的时候被执行。
3.2.2 LoadEnvironment()之f->Call()与 node.js之startup()
上面说到f->Call()的时候,是在V8里面解析执行了node.js返回来的匿名函数,来看一下该函数(图3-2-1)。
步骤1. 匿名函数的第一个步骤是给startup()函数挂载一堆初始化函数,比如processNext()。
步骤2. startup的相关初始化函数都挂载完之后,匿名函数执行最后一步,调用startup()。
步骤3. 看到startup()函数的定义,里面开始去执行这一堆挂载函数。processNext()里面所做的就是给process.nextTick赋值。就是我们平时用的process.nextTick了。
注:匿名函数的参数process是C++模块传进来的对象(也就是f->Call()传进来的参数)。
步骤4. startup()函数在执行完匿名函数挂载的一堆初始化函数之后,继而执行Module.runMain()。
3.2.3 Module.runMain()包装app.js文件
看到startup()函数在执行runMain()之前,对process.argv[1]里做了一下处理,这个argv就是node命令行启动的时候,main函数接收的参数。比如“node app.js”启动,argv[1]就保存着我们的js文件名了。
那么runMain()通过process.argv[1]去读取app.js文件,读成字符串,调用NativeModule.wrap()函数(图3-2-1),把我们的app.js代码包在里面。
这里就可以说明app.js代码里面为何生来就有require、exports、module这几个变量可以用了。其实是被放到一个 js函数里面了。
最后runMain()里面也是调用V8的Compile()、Run()等接口,去执行app.js代码。
node源码详解(三)的更多相关文章
- node源码详解(二 )—— 运行机制 、整体流程
		本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource2 本博客同步在https://cnodejs.o ... 
- node源码详解(三)—— js代码在node中的位置,process、require、module、exports的由来
		本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource3 本博客同步在https://cnodejs.o ... 
- node源码详解(五) —— 在main函数之前 —— js和C++的边界,process.binding
		本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource5 本博客同步在https://cnodejs.o ... 
- node源码详解(四) —— js代码如何调用C++的函数
		本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.o ... 
- node源码详解 (一)
		本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource1 本博客同步在https://cnodejs.o ... 
- node源码详解(四)
		本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.o ... 
- node源码详解(五)
		本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource5 本博客同步在https://cnodejs.o ... 
- OkHttp3源码详解(三) 拦截器-RetryAndFollowUpInterceptor
		最大恢复追逐次数: ; 处理的业务: 实例化StreamAllocation,初始化一个Socket连接对象,获取到输入/输出流()基于Okio 开启循环,执行下一个调用链(拦截器),等待返回结果(R ... 
- OkHttp3源码详解(三)  拦截器
		1.构造Demo 首先构造一个简单的异步网络访问Demo: OkHttpClient client = new OkHttpClient(); Request request = new Reques ... 
随机推荐
- 利用html sessionStorge 来保存局部页面在刷新后回显,保留
			转自:https://blog.csdn.net/u011085172/article/details/77320562 在一个页面里面,有个局部页面记录这当前session的任务记录,之前用的coo ... 
- angular2之pdf文件操作大全
			最近的项目中需要显示pdf内容.下载pdf.甚至是前端生成pdf 适用于angular2.4或者更高版本 情景1.需要将页面的某个部分转成pdf文件并下载(即将页面的部分html内容转成pdf文件) ... 
- [转] 理解 Dubbo SPI 扩展机制
			写在前面 最近接触了 gRPC 体会到虽然众多 RPC 框架各有各的特点但是他们提供的特性和功能有很多的相似之处 , 这就说明他们面对同样的分布式系统带来的问题.从 2016 年左右开始接触到 dub ... 
- [Swift]LeetCode1066. 校园自行车分配 II | Campus Bikes II
			★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ... 
- rabbitmq普通集群搭建详细步骤
			由于工作需求,需要安装rabbitmq,学习之余,记录一下安装过程 准备基础编译环境yum install gcc glibc-devel make ncurses-devel openssl-dev ... 
- JavaScript是按值传递还是按引用传递?
			JavaScript是按值传递的,但是要分情况才知道传递之后原来的值会不会变,不然会出现你想都想不出来的bug 一.按值传递--元类型输入tip:元类型( number, string, boolea ... 
- Ubuntu1804安装Postgresql【转】
			转载自:https://huur.cn/course/yw/1591.html 关系数据库管理系统是许多网站和应用程序的关键组成部分.它们提供了一种结构化的方式来存储,组织和访问信息. Postgre ... 
- vim的快捷键大全
			vim是开发利器,掌握快捷可以事半功倍,这里总结下常用的快捷键,提高开发速度这里写代码片 1.vim ~/.vimrc 进入配置文件 如果不知道vimrc文件在哪,可使用 :scriptnames 来 ... 
- android 将手机号中间隐藏为星号(*)
			){ StringBuilder sb =new StringBuilder(); ; i < pNumber.length(); i++) { char c = pNumber.charAt( ... 
- Android 概览屏幕
			文章照搬过来的:原文地址https://developer.android.google.cn/guide/components/recents.html 概览屏幕(也称为最新动态屏幕.最近任务列表或 ... 
