美文网首页
Node 核心和 Node eventLoop

Node 核心和 Node eventLoop

作者: 育儿与心理 | 来源:发表于2020-09-01 19:25 被阅读0次

    Node 核心和 Node eventLoop

    Node 是什么

    • Node.js 是一个开源与跨平台的 JavaScript 运行时环境;
    • Node.js 在浏览器外运行 V8 JavaScript 引擎(Google Chrome 的内核)
    • Node.js 应用程序运行于单个进程中,无需为每个请求创建新的线程
    • Node.js 在其标准库中提供了一组异步的 I/O 原生功能(用以防止 JavaScript 代码被阻塞),并且 Node.js 中的库通常是使用非阻塞的范式编写的(从而使阻塞行为成为例外而不是规范)
    • Node.js 执行 I/O 操作时(例如从网络读取、访问数据库或文件系统),Node.js 会在响应返回时恢复操作,而不是阻塞线程并浪费 CPU 循环等待
    • Node.js 又基于js核心 (ecmascript) 系统级的api 文件操作,网络编程 实现自己的 web 服务

    Node 解决了什么问题

    Web服务器,瓶颈在于用户的并发量 (多线程 同步) 只要多个人需要操作同一个资源必须通过锁

    • java php 用户访问服务器,每个客户连接服务器时 都会产生一个新的线程,一个线程大约占用 2mb 内存,8g 内存
    • node 不会创建新的线程,就发射一个事件
    • 前后端分离,写一些工具库 webpack,cli

    node 比较适合web应用场景 返回文件 文件读写

    Node核心特点

    • 事件驱动 Node.js 的 api 是基于事件的 异步的
    • Node.js 采用的是单线程 进程(主线程)node.js 可以开启多个进程
    • 不适合 cpu 密集型 i/o密集型

    同步异步 阻塞非阻塞(针对的点不一样的)

    • 同步和异步,关注的是消息通知的机制 readFile
      • 同步体现在,在等待一件事情的处理结果时,对方是否提供通知服务,如果对方不提供通知服务,则为同步
      • 异步体现在,在等待一件事情的处理结果时,对方是否提供通知服务,如果对方提供通知服务,则为异步。
    • 阻塞和非阻塞 程序等待消息结果的状态
      • 阻塞,在等待一件事情的处理结果时,你是否还去干点其他的事情,如果不去,则为阻塞;
      • 非阻塞,在等待一件事情的处理结果时,你是否还去干点其他的事情,如果去了,则为非阻塞;

    Node 中的全局对象

    this 和 module.exports 是 === 的

      console.log(this); // {} this 不是 global
      console.log(this === global); // false
      console.log(this === module.exports); // true
    

    arguments

      console.log(arguments);
      // [Arguments] {
      //   '0': {},
      //   '1': [Function: require] {
      //     resolve: [Function: resolve] { paths: [Function: paths] },
      //     main: Module {
      //       id: '.',
      //       path: '/Users/hiraku/myself/architecture-product/node/4.global',
      //       exports: {},
      //       parent: null,
      //       filename: '/Users/hiraku/myself/architecture-product/node/4.global/index.js',
      //       loaded: false,
      //       children: [],
      //       paths: [Array]
      //     },
      //     extensions: [Object: null prototype] {
      //       '.js': [Function],
      //       '.json': [Function],
      //       '.node': [Function],
      //       '.mjs': [Function]
      //     },
      //     cache: [Object: null prototype] {
      //       '/Users/hiraku/myself/architecture-product/node/4.global/index.js': [Module]
      //     }
      //   },
      //   '2': Module {
      //     id: '.',
      //     path: '/Users/hiraku/myself/architecture-product/node/4.global',
      //     exports: {},
      //     parent: null,
      //     filename: '/Users/hiraku/myself/architecture-product/node/4.global/index.js',
      //     loaded: false,
      //     children: [],
      //     paths: [
      //       '/Users/hiraku/myself/architecture-product/node/4.global/node_modules',
      //       '/Users/hiraku/myself/architecture-product/node/node_modules',
      //       '/Users/hiraku/myself/architecture-product/node_modules',
      //       '/Users/hiraku/myself/node_modules',
      //       '/Users/hiraku/node_modules',
      //       '/Users/node_modules',
      //       '/node_modules'
      //     ]
      //   },
      //   '3': '/Users/hiraku/myself/architecture-product/node/4.global/index.js',
      //   '4': '/Users/hiraku/myself/architecture-product/node/4.global'
      // }
    

    global key

      console.log(Object.keys(global));
      // [
      //   'global',
      //   'clearInterval',
      //   'clearTimeout',
      //   'setInterval',
      //   'setTimeout',
      //   'queueMicrotask',
      //   'clearImmediate',
      //   'setImmediate'
      // ]
    

    process 进程

      console.log(Object.keys(process));
      // ['version','arch','platform','release','_rawDebug','moduleLoadList','binding','_linkedBinding','_events','_eventsCount','_maxListeners','domain','_exiting','config','abort','umask','chdir','cwd','_debugProcess','_debugEnd','_startProfilerIdleNotifier','_stopProfilerIdleNotifier','dlopen','uptime','_getActiveRequests','_getActiveHandles','reallyExit','_kill','hrtime','cpuUsage','resourceUsage','memoryUsage','kill','exit','getuid','geteuid','getgid','getegid','getgroups','initgroups','setgroups','setegid','seteuid','setgid','setuid','stdout','stderr','stdin','openStdin','allowedNodeEnvironmentFlags','assert','features','_fatalException','setUncaughtExceptionCaptureCallback','hasUncaughtExceptionCaptureCallback','emitWarning','nextTick','_tickCallback','env','title','argv','execArgv','pid','ppid','execPath','debugPort','argv0','_preload_modules','mainModule'
    
    • process.argv
      // node index.js --port 3000
      console.log(process.argv);
      // 1. 当前 node 的执行命令文件
      // 2. 当前执行的文件是谁 node + 文件执行时 可以传递参数 这些参数会放到 数组的第三项
      // 3. 解析用户传递的参数
      // [ '/Users/hiraku/.nvm/versions/node/v11.10.0/bin/node',
      //   '/Users/hiraku/myself/architecture-product/node/global/index.js',
      //   '--port',
      //   '3000' ]
      const argvObj = process.argv.slice(2).reduce((memo, current, index, arr) => {
        if(current.startsWith('--')) {
          memo[current.slice(2)] = arr[index + 1];
        }
        return memo;
      }, {});
      console.log(argvObj);
    
    • process.platform 进程运行的平台
      console.log(process.platform, 'platform'); // darwin
      // win32 darwin
    
    • commander 的使用
      const cmd = require('commander');
      cmd.name('node global');
      cmd.usage('index.js');
      cmd.version('1.0.0');
      cmd.option('-p,--port <v>', 'please set you prot ');
      cmd.option('-c,--config <v>', 'please set  you config file ');
      cmd.command('create').action(() => { // 运行时会执行此方法
          console.log('创建项目');
      });
      cmd.on('--help', function () {
          console.log('\r\nRun command')
          console.log('\r\n  node global -p 3000')
      });
      const r = cmd.parse(process.argv);
      console.log(r);
      console.log(process.env);
      console.log(process.cwd());
    
      // Usage: node global index.js
    
      // Options:
      //   -V, --version    output the version number
      //   -p,--port <v>    please set you prot
      //   -c,--config <v>  please set  you config file
      //   -h, --help       display help for command
    
      // Commands:
      //   create
      //   help [command]   display help for command
    
      // Run command
    
      //   node global -p 3000
    
    • process.cwd 当前工作目录,如 webpack 找配置文件,当前工作目录下查找
      console.log(process.cwd()); // /Users/hiraku/myself/architecture-product/node/4.global
    
    • 在当前命令行窗口下设置环境变量
    // window set命令 export 命令  => cross-env
    console.log(process.env) // 当前进程的环境变量 会用他来区分各种环境
    // cross-env env=development && node xxxx
    

    Node 中的实现的微任务

    • node 中实现的微任务 他的优先级比 promise 还要高
    • nextTick 和 promise 是两个队列,所以会先清空 nextTick 队列
    • node 的事件环 在 nodeV10 版本之后,统一执行效果和浏览器一致,每个宏任务执行完都会清空微任务
    • 老版本是每个队列清空后清空微任务
      process.nextTick(() => {
        console.log(1);
        process.nextTick(() => {
          console.log(2);
          process.nextTick(() => {
            console.log(3);
          });
        });
      });
      Promise.resolve().then(() => {
        console.log('promise')
      });
    
      // 1 2 3 promise
    
    • 如果是 setImmediate 和 setTimeout 在默认环境下执行会受性能影响
      setImmediate(() => { // 立即
        console.log('setImmediate'); // node 中的宏任务
      });
      setTimeout(() => {
        console.log('setTimeout');
      }, 0);
      // setTimeout
      // setImmediate
    
    • setImmediate nextTick
      setImmediate(() => {
        console.log('setImmediate1');
        process.nextTick(() => {
          Promise.resolve().then(() => {
            console.log('promise1');
          });
        });
      });
      setImmediate(() => {
        console.log('setImmediate2');
        Promise.resolve().then(() => {
          console.log('promise2');
        });
        process.nextTick(() => {
          console.log('nextTick2');
        });
      });
      process.nextTick(() => {
        console.log('nextTick1');
      });
    
      // nextTick1
      // setImmediate1
      // promise1
      // setImmediate2
      // nextTick2
      // promise2
    
    • 总结
      • 默认当主代码执行完毕后会进入到事件环
      • 会先看当前定时器是否到达时间,如果到达时间会执行 定时器的回调
      • poll 阶段会执行 i/o 操作的回调,如果没有 i/o 看一下有没有 setImmediate,如果有会进入到 check 阶段
      • 如果没有 要检查是否有定时器如果没定时器也没有,i/o操作则结束循环
      • 如果有定时器,定时器到达时间后,会返回 timer 阶段执行定时器的回调
      • 每一个宏任务执行完毕后都会清空微任务
    企业微信20200901-190600@2x.png
    • 定时器:本阶段执行已经被 setTimeout() 和 setInterval() 的调度回调函数。

    • 待定回调:执行延迟到下一个循环迭代的 I/O 回调。

    • idle, prepare:仅系统内部使用。

    • 轮询:检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 * setImmediate() 调度的之外),其余情况 node 将在适当的时候在此阻塞。

    • 检测:setImmediate() 回调函数在这里执行。

    • 关闭的回调函数:一些关闭的回调函数,如:socket.on('close', ...)。

    • 宏任务微任务分类

      • Vue.nextTick 混合型任务,可能是微任务也可能是宏任务
      • 微任务 promise.then、mutationObserver、process.nextTick
      • 宏任务 script 标签、ui 渲染 、MessageChannel(浏览器) 、ajax、event 事件、setTimeout
      • setImmediate requestFrameAnimation
      • 浏览器是一个宏任务队列 node 是多个宏任务队列
      • 执行顺序是一样的

    相关文章

      网友评论

          本文标题:Node 核心和 Node eventLoop

          本文链接:https://www.haomeiwen.com/subject/rgxbsktx.html