本作品采用知识共享署名 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源码详解(三)的更多相关文章

  1. node源码详解(二 )—— 运行机制 、整体流程

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource2 本博客同步在https://cnodejs.o ...

  2. node源码详解(三)—— js代码在node中的位置,process、require、module、exports的由来

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource3 本博客同步在https://cnodejs.o ...

  3. node源码详解(五) —— 在main函数之前 —— js和C++的边界,process.binding

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource5 本博客同步在https://cnodejs.o ...

  4. node源码详解(四) —— js代码如何调用C++的函数

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.o ...

  5. node源码详解 (一)

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource1 本博客同步在https://cnodejs.o ...

  6. node源码详解(四)

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.o ...

  7. node源码详解(五)

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource5 本博客同步在https://cnodejs.o ...

  8. OkHttp3源码详解(三) 拦截器-RetryAndFollowUpInterceptor

    最大恢复追逐次数: ; 处理的业务: 实例化StreamAllocation,初始化一个Socket连接对象,获取到输入/输出流()基于Okio 开启循环,执行下一个调用链(拦截器),等待返回结果(R ...

  9. OkHttp3源码详解(三) 拦截器

    1.构造Demo 首先构造一个简单的异步网络访问Demo: OkHttpClient client = new OkHttpClient(); Request request = new Reques ...

随机推荐

  1. iOS APP开发概述----学习笔记001

    之前开发过一些Android APP,如今開始学习iOS开发,未来实际工作应该会用到.未雨绸缪. 一.了解其系统层次架构 其系统分层四层,其具体例如以下: 第一层:Core OS watermark/ ...

  2. Linux(redhat 5.8)下 安装jetty 部署 使用

    首先须要安装JDK,自行解决 下载jetty安装包http://dist.codehaus.org/jetty/ 我下载的是8.1.15 tar -xzvf *.tar.gz 解压完之后,基本就能够用 ...

  3. 10.0arcmap切片生成ptk步骤

    注意:在制作之前需要点将图放到原本大小.并且保存一下不然容易造成数据丢失. 1.制作mxd 我们将待发布的数据,鼠标选中,拖入到ArcMap中间区域,单击保存. 可以对layers下面的图层进行改名. ...

  4. codeforces 782B The Meeting Place Cannot Be Changed+hdu 4355+hdu 2438 (三分)

                                                                   B. The Meeting Place Cannot Be Change ...

  5. python关于文件的操作

    总是记不住API.昨晚写的时候用到了这些,但是没记住,于是就索性整理一下吧: python中对文件.文件夹(文件操作函数)的操作需要涉及到os模块和shutil模块. 得到当前工作目录,即当前Pyth ...

  6. 截取字符(substr)检索字符位置(instr)

    1.SUBSTR(string,start_position,[length]) 求子字符串,返回字符串注释: string 元字符串start_position 开始位置(从0开始)length 可 ...

  7. poj3233Matrix Power Series(矩阵乘法)

    Matrix Power Series Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 23187   Accepted: ...

  8. Rancher 2:添加 NFS client provisioner 动态提供 Kubernetes 后端存储卷

    一.前提说明 1.说明: NFS client provisioner 利用 NFS Server 给 Kubernetes 作为持久存储的后端,并且动态提供PV. 默认 rancher 2 的存储类 ...

  9. 3.朴素贝叶斯和KNN算法的推导和python实现

    前面一个博客我们用Scikit-Learn实现了中文文本分类的全过程,这篇博客,着重分析项目最核心的部分分类算法:朴素贝叶斯算法以及KNN算法的基本原理和简单python实现. 3.1 贝叶斯公式的推 ...

  10. python 进程理论基础

    背景知识 顾名思义,进程即一个软件正在进行的过程.进程是对正在运行的程序的一个抽象 进程的概念起源于操作系统,是操作系统的最核心的概念,也是操作系统提供的最古老的也是最重要的抽象概念之一.操作系统的其 ...