zoukankan      html  css  js  c++  java
  • 编译nodejs及其源代码研究

    本文将从 源代码 研究nodejs 的原理、本质,探讨nodejs的应用场景,以及高性能开发实践指南。

    文件夹:

    第一节:编译node.js 

    第二节:源代码分析


    进入主题:下面是在win7 64 下进行,其它平台编译 。请參见官网。

    第一节:编译node.js,过程非常easy

    1、下载源代码。  git clone https://github.com/joyent/node

    假设没有安装gitclient,能够在打开https://github.com/joyent/node  点击 Download ZIP,进行下载

    2、安装 Python 2.6 or 2.7 和 Visual Studio 2010 or 2012。我这里是 Python 2.7.8  和 Visual Studio 2012

    3、进入node文件夹  运行 vcbuild release


    大概 10多分钟 就能够编译成功。在Release文件夹下会生成node.exe。以下是我编译成功的图。



     第二节:源代码分析

    我们在IDE 中 打开刚才的node文件夹,方便我们看源代码。

    我这里是Idea查看。


    benchmark : 一些nodejs 性能測试 代码

    build:编译nodejs 生成文件夹

    Debug:编译nodejs 生成文件夹

    Release:编译nodejs 生成文件夹

    deps:nodejs依赖 的工具包。包含 v8、http_parser、opensslzlib、zlib、uv。

    。。

    doc:文档

    lib:包括JavaScript源代码

    src:包括C++源代码

    test:測试代码

    tools:编译时用到的工具

    这里我们仅仅需关注 src 和lib 目录。


    1、从node.cc 文件 看 node进程 启动过程的

    int Start(int argc, char** argv) {
      const char* replaceInvalid = getenv("NODE_INVALID_UTF8");
    
      if (replaceInvalid == NULL)
        WRITE_UTF8_FLAGS |= String::REPLACE_INVALID_UTF8;
    
    #if !defined(_WIN32)
      // Try hard not to lose SIGUSR1 signals during the bootstrap process.
      InstallEarlyDebugSignalHandler();
    #endif
    
      assert(argc > 0);
    
      // Hack around with the argv pointer. Used for process.title = "blah".
      argv = uv_setup_args(argc, argv);
    
      // This needs to run *before* V8::Initialize().  The const_cast is not
      // optional, in case you're wondering.
      int exec_argc;
      const char** exec_argv;
      Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
    
    #if HAVE_OPENSSL
      // V8 on Windows doesn't have a good source of entropy. Seed it from
      // OpenSSL's pool.
      V8::SetEntropySource(crypto::EntropySource);
    #endif
    
      int code;
      V8::Initialize();
      {
        Locker locker(node_isolate);
        Isolate::Scope isolate_scope(node_isolate);
        HandleScope handle_scope(node_isolate);
        Local<Context> context = Context::New(node_isolate);
        Environment* env = CreateEnvironment(
            node_isolate, context, argc, argv, exec_argc, exec_argv);
        // Assign env to the debugger's context
        if (debugger_running) {
          HandleScope scope(env->isolate());
          env->AssignToContext(v8::Debug::GetDebugContext());
        }
        // This Context::Scope is here so EnableDebug() can look up the current
        // environment with Environment::GetCurrent().
        // TODO(bnoordhuis) Reorder the debugger initialization logic so it can
        // be removed.
        {
          Context::Scope context_scope(env->context());
          bool more;
          do {
            more = uv_run(env->event_loop(), UV_RUN_ONCE);
            if (more == false) {
              EmitBeforeExit(env);
    
              // Emit `beforeExit` if the loop became alive either after emitting
              // event, or after running some callbacks.
              more = uv_loop_alive(env->event_loop());
              if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
                more = true;
            }
          } while (more == true);
          code = EmitExit(env);
          RunAtExit(env);
        }
        env->Dispose();
        env = NULL;
      }
    
      CHECK_NE(node_isolate, NULL);
      node_isolate->Dispose();
      node_isolate = NULL;
      V8::Dispose();
    
      delete[] exec_argv;
      exec_argv = NULL;
    
      return code;
    }

    Environment* CreateEnvironment(Isolate* isolate,
                                   Handle<Context> context,
                                   int argc,
                                   const char* const* argv,
                                   int exec_argc,
                                   const char* const* exec_argv) {
      HandleScope handle_scope(isolate);
    
      Context::Scope context_scope(context);
      Environment* env = Environment::New(context);
    
      uv_check_init(env->event_loop(), env->immediate_check_handle());
      uv_unref(
          reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()));
      uv_idle_init(env->event_loop(), env->immediate_idle_handle());
    
      // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
      // but not all samples are created equal; mark the wall clock time spent in
      // epoll_wait() and friends so profiling tools can filter it out.  The samples
      // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
      // TODO(bnoordhuis) Depends on a libuv implementation detail that we should
      // probably fortify in the API contract, namely that the last started prepare
      // or check watcher runs first.  It's not 100% foolproof; if an add-on starts
      // a prepare or check watcher after us, any samples attributed to its callback
      // will be recorded with state=IDLE.
      uv_prepare_init(env->event_loop(), env->idle_prepare_handle());
      uv_check_init(env->event_loop(), env->idle_check_handle());
      uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle()));
      uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_check_handle()));
    
      if (v8_is_profiling) {
        StartProfilerIdleNotifier(env);
      }
    
      Local<FunctionTemplate> process_template = FunctionTemplate::New(isolate);
      process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process"));
    
      Local<Object> process_object = process_template->GetFunction()->NewInstance();
      env->set_process_object(process_object);
    
      SetupProcessObject(env, argc, argv, exec_argc, exec_argv);
      Load(env);
    
      return env;
    }

    void SetupProcessObject(Environment* env,
                            int argc,
                            const char* const* argv,
                            int exec_argc,
                            const char* const* exec_argv) {
      HandleScope scope(env->isolate());
    
      Local<Object> process = env->process_object();
    
      process->SetAccessor(env->title_string(),
                           ProcessTitleGetter,
                           ProcessTitleSetter);
    
      // process.version
      READONLY_PROPERTY(process,
                        "version",
                        FIXED_ONE_BYTE_STRING(env->isolate(), NODE_VERSION));
    
      // process.moduleLoadList
      READONLY_PROPERTY(process,
                        "moduleLoadList",
                        env->module_load_list_array());
    
      // process.versions
      Local<Object> versions = Object::New(env->isolate());
      READONLY_PROPERTY(process, "versions", versions);
    
      const char http_parser_version[] = NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR)
                                         "."
                                         NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR);
      READONLY_PROPERTY(versions,
                        "http_parser",
                        FIXED_ONE_BYTE_STRING(env->isolate(), http_parser_version));
    
      // +1 to get rid of the leading 'v'
      READONLY_PROPERTY(versions,
                        "node",
                        OneByteString(env->isolate(), NODE_VERSION + 1));
      READONLY_PROPERTY(versions,
                        "v8",
                        OneByteString(env->isolate(), V8::GetVersion()));
      READONLY_PROPERTY(versions,
                        "uv",
                        OneByteString(env->isolate(), uv_version_string()));
      READONLY_PROPERTY(versions,
                        "zlib",
                        FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION));
    
      const char node_modules_version[] = NODE_STRINGIFY(NODE_MODULE_VERSION);
      READONLY_PROPERTY(
          versions,
          "modules",
          FIXED_ONE_BYTE_STRING(env->isolate(), node_modules_version));

    void Load(Environment* env) {
      HandleScope handle_scope(env->isolate());
    
      // Compile, execute the src/node.js file. (Which was included as static C
      // string in node_natives.h. 'natve_node' is the string containing that
      // source code.)
    
      // The node.js file returns a function 'f'
      atexit(AtExit);
    
      TryCatch try_catch;
    
      // Disable verbose mode to stop FatalException() handler from trying
      // to handle the exception. Errors this early in the start-up phase
      // are not safe to ignore.
      try_catch.SetVerbose(false);
    
      Local<String> script_name = FIXED_ONE_BYTE_STRING(env->isolate(), "node.js");
      Local<Value> f_value = ExecuteString(env, MainSource(env), script_name);
      if (try_catch.HasCaught())  {
        ReportException(env, try_catch);
        exit(10);
      }
      assert(f_value->IsFunction());
      Local<Function> f = Local<Function>::Cast(f_value);
    
      // Now we call 'f' with the 'process' variable that we've built up with
      // all our bindings. Inside node.js we'll take care of assigning things to
      // their places.
    
      // We start the process this way in order to be more modular. Developers
      // who do not like how 'src/node.js' setups the module system but do like
      // Node's I/O bindings may want to replace 'f' with their own function.
    
      // Add a reference to the global object
      Local<Object> global = env->context()->Global();


    大致的过程是这种 :

    载入 V8 、OpenSSL ... 

    创建 Environment 环境

    设置 Process 进程对象

    运行 node.js 文件


    2、从 node.js 文件 看 global 配置过程。吐槽一下,nodejs的源代码写的太搓了。C系语言出生的风格?

    这个文件大致是 是配置 全局变量、配置process、定义模块对象。


    后面将深入 解说 node.js 这个文件 、以及结合 src 的C++类,与lib 下的 js代码 解说nodejs。

    我们能够得出一个结论: nodejs  = node API + V8;




  • 相关阅读:
    HTTP 与 HTTPS 的区别
    cookie 和session 的区别详解
    IntelliJ远程调试教程
    selenium 自动化测试面试题及答案
    性能测试总结(一)---基础理论篇(转载)
    性能测试总结(二)---测试流程篇(转载)
    性能测试总结(三)--工具选型篇
    eclipse调试的基本意义
    控制反转(IOC)和依赖注入(DI)
    前端框架layui
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5089971.html
Copyright © 2011-2022 走看看