• nodejs全局对象简析


    • Global:全局变量
    • 定时器、控制台输出、事件
    • 模块化相关的一些全局变量
    • path/url相关的一些全局变量
    • 编码相关的
    • buffer:缓存(简单介绍)
    • Process:进程(重点解析)

     一、Global

    Global与浏览器中的全局对象window的功能非常类似,可以简单的理解为提供在开发过程任意地方供调用的属性、方法、对象,不需要做任何引入创建等操作。由于nodejs是一个服务端平台而浏览器是客户端平台,它们在具体的功能上肯定有很大的差异,但也有基于JS的完全相同的一些功能。

    1.1定时器、控制台输出、事件

    这些都是基础的JS內置功能,这与浏览器上的window表面上没有任何差异,但由于nodejs与浏览器的实现目的差异,在底层上这些功能nodejs相比浏览器提供了更多可扩展性空间,比如控制台输出的console.log可以在基于流的基础上做很多扩展。

    -- 定时器:(具体参考官方文档timers)

    setImmediate(call[,..arg]):事件结束时调用异步任务

    clearImmediate(immediate):用于取消setImmediate任务

    //setImmediate在事件循环结束时调用(异步),可以将他理解为一个立即调用的异步任务
    //返回Immediate,可以使用clearImmediate控制该回调是否保持或取消,
    let imm = setImmediate(function(args){
        console.log(args);
    },"事件结束后我被调用了");
    clearImmediate(imm);//这里同步任务上取消了imm,所以不会调用(可以注释这一行代码看看它的执行效果)

    余下的setInterval、setTimeout、clearInterval、clearTimeout这些就不用介绍了,在浏览器中都是使用非常频繁的。当然浏览器中也有Immediate的两个API,只是大部分浏览器不兼容而已。

    -- 控制台输出、事件

    console、Event、EventTarget这些同样在浏览器中都有,就不做过多介绍了,但后面会有博客就nodejs的事件机制做具体的分析。

    1.2模块化相关的全局API

    exports、module、require、require()这些在之前的这篇博客中有初步应用的介绍,如果需要了解可以查看详细内容:nodejs入门之模块。后面会有博客针对nodejs的commondjs规范做详细解析,也会包含这些API的使用。

    1.3path/url

    console.log(__dirname);//当前模块的目录(相对于项目的根目录)
    console.log(__filename);//当前模块的文件名称(包含目录节点分隔符和后缀“\index.js”)

    URL、URLSearchParams是nodejs內置的网址模块内容,在之前有一篇博客详细的分析了这部分内容:nodejs入门API之url模块+querystring模块

    1.4编码相关的

    在全局上有TextDecoder、TextEncoder这两个类,它们是用于处理编码相关的內置模块,后面会有详细解析nodejs编码相关的博客。

    1.5buffer缓存

    用于处理二进制数据,这是在nodejs中一个相对重要的内容,后面会有专门的博客解析,到之后写完再来粘贴链接。

     二、Process(进程)

    process对象是提供当前nodejs进程的信息,并对其控制管理的內置全局模块。

    首先在进入process具体的解析前做一些说明,由于这一篇博客重点在介绍nodejs的全局对象,所以这里只对process做基本使用的解析,不会涉及nodejs的进程管理和其原理做分析,后面会有一篇专门分析nodejs进程管理底层原理及相关的服务架构内容博客。

    2.1获取当前进程的信息:cpu 、内存

    -- process.memoryUsage():返回描述当前nodejs进程的内存使用量(以字节为单位)

    process.memoryUsage();
    //返回结果
    {
        rss: 18866176,          //常驻内存大小
        heapTotal: 4014080,     //当前v8申请使用的总的内存大小
        heapUsed: 2278552,      //当前脚本实际使用的内存大小
        external: 801290,       //扩展的内存大小
        arrayBuffers: 9382      //独立的空间大小(不占用v8申请使用的内存大小)
    }

    RSS:常驻内存大小,是进程在主内存设备中占用的空间量,包括C++和JavaScript对象和代码,意思就是当前进程实在内存设备中分配到了多少内存供自己使用,比如示例中实际分到了18866176个字节的内存供自己使用。

    heapTotal:当前v8申请使用的总的内存大小,也就是指当前进程运行实际使用了RSS多少内存,比如示例中的信息可以看到当前进程使用了常驻内存的4014080个字节,由此我们可以得出当前常驻内存还剩18866176-4014080=14852096个字节的内存没有被使用。然后我们需要知道这个使用的内存包含了当前进程的JS代码和c/c++的总内存,在前面一节nodejs入门第一节课中解析的nodejs的内部架构,除了javaScript模块还有底层的C/C++等模块,所以在memoryUsage打印的结果中还包含了heapUsed和external两个内存信息,它们分别代表JS模块和c/c++扩展模块的内存使用信息。

    heapUsed:当前脚本使用的内存大小,这里我们就可以通过引入一个模块来测试这个内存信息的变化:

    const fs = require('fs');
    process.memoryUsage();
    {
      rss: 19304448,     
      heapTotal: 4276224,
      heapUsed: 2490984, 
      external: 941238,  
      arrayBuffers: 9382 
    }

    你会发现当引入了fs模块后heapUsed的内存明显多出了很多:2490984-2278552=212432字节。但同时也发现external也有变化:941238-801290=139948,这是因为在引入fs模块时候node在底层就会添加与fs模块相关的C/C++模块,用来准备处理fs模块的相关对象和接口。

    external:扩展内存大小,通过前面的heapUsed大概就能明白它的含义,实际上就是v8管理JavaScript对象的C/C++对象的内存使用量,所以这就是但引入fs模块后external也会增长的原因。

    arrayBuffers:独立的内存空间大小,不占用v8自动申请的内存,也就是说arrayBuffers的内存不在srr的内存计算范围内。比如可以使用下面的代码申请一个独立内存,但是你会发现srr的内存也发生了变化,这跟之前引入fs模块的情况类似,这是因为v8会根据你引入的模块在底层加载相应的处理模块,并且当前脚本上还会加载Buffer相关js模块的内容,所以其他值也会跟着发生变化,关于独立内存的使用会在Buffer中介绍,后期还会有关于内存管理的博客详细解析。

    Buffer.alloc(1000);    //申请独立内存空间
    console.log(process.memoryUsage());

    2.2运行环境:运行目录、node环境、cpu架构、用户环境、系统平台、环境标志、可配置文件、node元数据、当前node可执行文件的绝对路径

    -- process.cwd():运行目录

    //当前的进程的工作目录,即当前代码所在的文件的目录
    console.log(process.cwd());

    在node上有一个方法可以改变当前进程的工作目录:process.chdir(directory),参数就是需要更改目标目录的绝对路径字符串。

    -- process.version:当前node环境,即当前执行项目的node版本号。

    //当前的node环境,即当前执行项目的node的版本号
    console.log(process.version);   //v14.4.0
    console.log(process.versions);   //详细的node环境信息,包含了node、v8、uv、zlib、brotli、ares、modules、nghttp2、napi、llhttp、openssl、cldr、icu、tz、unicode这些底层模块的版本信息

    -- process.arch:CPU架构

    //CPU架构
    console.log(process.arch);  //x64--即当前设备的CPU架构为64位操作系统

    -- process.env:用户环境,这里包含的信息比较多,主要是一些路径信息,在前端工程中的应用主要是用来配置生产环境和开发环境。

    //用户环境
    console.log(process.env);
    console.log(process.env.PATH);//当前本机的环境变量
    console.log(process.env.USERPROFILE);   //本机管理员目录,这个信息根操作系统有关,如果是mac平台关键字就是HOME
    console.log(process.env.NODE_ENV);//通常用来配置开发或生成环境信息,没有配置的情况下返回undefined

    -- process.platform:系统平台

    console.log(process.platform);  //win32

    -- process.allowedNodeEnvironmentFlags:当前环境所有环境标志的set对象。所谓环境标志就是在使用node命令执行脚本时输入的如:node --max-old-space-size=1536 表示当前启动的node进程最大未1.5GB。详细参考官方文档的CLI命令部分。

    process.allowedNodeEnvironmentFlags.forEach((flag)=>{
        console.log(flag);
    });

    -- process.config:当前node执行的可配置文件内容。这与运行 ./configure 脚本时生成的 config.gypi 文件相同。

    console.log(process.config);

    -- process.release:当前node版本相关元数据。

    console.log(process.release);

    -- process.execPath:当前node可执行文件的绝对路径。

    2.3运行状态:启动参数、PID、运行时间、测试性能、当前进程资源的情况、更改当前进程的工作目录、当前进程debug的调试端口、设置或获取当前进程的掩码

    -- process.argv:启动参数,这个属性返回一个数组,第一个元素是当前node程序所在的目录,第二个元素是当前脚本的完整路径,后面的就是启动命令时后面依次添加的参数信息,比如下面的示例:

    //测试命令:node .\index.js a b
    console.log(process.argv);
    //打印结果:
    [
        'F:\\nodejs\\node.exe',
        'E:\\node\\process进程\\index.js',
        'a',
        'b'
    ]

    -- process.pid:当前进程的PID。

    console.log(process.pid);//当前进程的PID,可以通过这个PID在任务管理器中查找到任务的相关信息

    比如windows可以通过任务管理器面板查看,但要注意由于你当前的执行进程是执行后立即关闭的,那就无法查看到。如果你这时候启动了对一个端口的监听,程序没有关闭就可以查看到。除了直接在任务管理器面板中查看还可以通过控制台查看,具体操作就不演示了。

    -- process.title:当前进程的标题。即上面截图的名称值,也可以通过该属性自定义名称,注意标题在部分系统下有长度限制。

     -- process.ppid:当前进程的父进程PID。这篇博客没有介绍子进程,就不演示了了,在后期的nodejs进程管理的博客中会有具体的应用何解析。

    -- process.uptime():当前进程运行的秒数(注意这个时间单位是“秒”)。

    setTimeout(()=>{
        console.log(process.uptime());  //当前进程的执行时间(单位:秒)
    },3000);

    --process.cpuUsage([previousValue]):但概念进程的用户代码和系统代码分别在CPU上运行的时间,参数previousValue就是这个方法的返回值,当传入这个参数时该方法会得到减去传入值的返回值,意思就是当前这段执行用户代码和系统代码在CPU上运行的时间,返回数据单位为毫秒。

    let startUsage = process.cpuUsage();
    console.log(startUsage);
    let now = Date.now();
    while (Date.now() - now < 500);
    console.log(process.cpuUsage(startUsage));
    console.log(process.cpuUsage());

    --process.hrtime.bigint():当前进程运行的时间(高解析度:纳秒)

     1 //这些时间相对于过去的任意时间,与一天中的时间无关,因此不受时钟漂移的影响。 主要用途是测量间隔之间的性能
     2 import { hrtime } from 'process';
     3 
     4 const start = hrtime.bigint();
     5 // 191051479007711n
     6 
     7 setTimeout(() => {
     8   const end = hrtime.bigint();
     9   // 191052633396993n
    10 
    11   console.log(`Benchmark took ${end - start} nanoseconds`);
    12   // 基准测试耗时 1154389282 纳秒
    13 }, 1000);
    View Code

    --process.resourceUsage():当前进程资源的情况,比如使用的内存容量、用户代码使用cpu时间、系统代码使用的cpu时间等。

    console.log(process.resourceUsage());   //当前进程资源的情况

    -- process.chdir(directory);//更改当前进程的工作目录。

    -- process.debugPort:设置node启动debug的调试端口,可以通过改属性获取或设置debug的端口。

    -- process.umask(mask):设置或获取当前进程的掩码。

    1 import { umask } from 'process';
    2 
    3 const newmask = 0o022;
    4 const oldmask = umask(newmask);
    5 console.log(
    6   `Changed umask from ${oldmask.toString(8)} to ${newmask.toString(8)}`
    7 );
    View Code

    2.4进程事件:

    -- exit:退出当前进程事件。

    process.on('exit',(code)=>{ //当进程退出时触发该事件回调。code为事件状态码。
        console.log('exit:' + code);
    });

    进程退出状态码:默认状态码为0,该状态码可以通过process.exit(code)主动退出进程来设置,还可以通过process.exitCode属性来设置退出状态码。

    退出当前进程的三种情况:事件循环不在需要执行任何额外工作自动退出进程、使用process.exit()结束进程的显式调用手动退出进程、使用process.abort()退出文件,这个方法退出进程不会触发exit事件,但会生成一个核心文件。

    process.abort();//退出当前进程并生成一个核心文件,但要注意的是不会触发exit事件

    注意:退出当前进程事件回调中不能使用异步任务,因为主进程结束后使得事件循环中排队的其他工作会被丢弃。

    -- beforeExit:退出当前进程前的事件任务。

    process.on('beforeExit',(code)=>{//在进程退出前触发该事件回调,code为事件状态码
        console.log('befor exit:'+ code);
    });

    这个回调同样会接收到退出状态码,与exit事件差不多,但需要特别注意的是这个回调内部如果使用了异步任务,会导致进程无法退出,这是因为当你每一次执行完beforeExit异步任务后,主进程又启动了新的beforeExit任务。

    -- message:进程消息事件,即两个进程之间通过process.send()向另一个经常发送消息时,另一个接收消息的message事件被触发,message事件回调接收的参数就是send传入的实参。假设现在有一个主进程parent.js和子进程sub.js如下方示例:

     1 //parent.js --主线程
     2 const cp = require('child_process');    //引入子进程模块
     3 let n = cp.fork(__dirname + '/sub.js'); //通过fork加载子进程sub.js
     4 n.on('message',function(m){             //在主进程上注册一个监听子进程sub.js的send发来的消息
     5     console.log('PARENT got message:' , m);
     6 });
     7 n.send({hello:'world'});                //在主进程上给子线程sub.js发送消息
     8 
     9 //sub.js -- 子进程
    10 process.on('message',function(m){        //注册一个监听父进程send发送来的消息事件
    11     console.log('CHILD got message:',m);
    12 });
    13 
    14 process.send({foo:'bar'});               //向父进程发送消息

    关于process上的message事件有几个相关的API和模块:

    process.send():负责向子进程发送消息;

    process.on('message',fun):负责监听父级进程的send发送过来的消息;

    child_process:子进程模块;

    child_processObj.fork():创建子进程,在child_process模块上创建子进程的方法总共有四个,这里展示不介绍了,在后面的nodejs进程管理那篇博客中具体的解析。

    child_processObj.send():在主进程上向子进程child_processObj发送消息;

    child_processObj.on('message', fun):在主进程上监听子进程child_processObj通过send发送过来的消息。

    这里需要注意,在示例中的主进程和子进程上的message事件触发没有先后顺序,这是因为它们分属不同的进程,它们通过send发出的消息都会被丢到事件轮询管理机制内,然后再有事件轮询机制响应给它们然后触发它们的事件回调任务,这个现后顺序简单的说一个随机概率,严格来说是要看它们的进程什么时候收到事件轮询机制的响应。(所以你可以通过多次启动主进程来查看打印结果,绝对会出现打印先后顺序不一致的情况)

    -- disconnect:关闭与父级进程的通信通道事件,该方法由子进程上的process.disconnect()或父级进程下的child_processObj.disconnect()关闭与父级进程的通信通道时触发。比如还是使用上面的主进程parent.js和子进程sub.js示例:

     1 //parent.js -- 主进程
     2 const cp = require('child_process');    //引入子进程模块
     3 let n = cp.fork(__dirname + '/sub.js'); //通过fork加载子进程sub.js
     4 n.on('message',function(m){             //在主进程上注册一个监听子进程sub.js的send发来的消息
     5     console.log('PARENT got message:' , m);
     6     n.disconnect();                     //在主进程上关闭子进程sub.js与父级parent.js(当前主进程)的通信通道
     7 });
     8 n.send({hello:'world'});                //在主进程上给子线程sub.js发送消息
     9 
    10 //sub.js -- 子进程
    11 process.on('message',function(m){       //注册一个监听父进程send发送来的消息事件
    12     console.log('CHILD got message:',m);
    13     process.disconnect();               //在子进程上关闭与父进程的通信通道
    14 });
    15 process.on('disconnect',function(){
    16     console.log('子进程sub.js与父进程通信通道关闭');
    17 });
    18 process.send({foo:'bar'});              //向父进程发送消息

    2.5监听promise的一些风险行为的事件(这依然是process上的事件)

    -- multipleResolves事件:用于解决在Promise构造中可能出现的潜在错误问题,当Promise构造中出现这四种情况时,该事件会被触发。

    第一种情况:解决多次,即在Promise构造中一个逻辑下出现多次调用resole,以下示例:

     1 process.on('multipleResolves',(type,promise,reason)=>{
     2     console.error(type,promise,reason);
     3 });
     4 function main(){
     5     return  new Promise((resole, reject) => {
     6         resole("First call");
     7         resole('Swallowed resolve');
     8     });
     9 }
    10 main().then(console.log,console.log);
    11 //打印结果
    12 //multipleResolves事件被触发: resolve Promise { 'First call' } Swallowed resolve
    13 //then的解决受理:First call

    第二种情况:拒绝多次,即在Promise构造中一个逻辑下出现多次调用reject,以下示例:

     1 process.on('multipleResolves',(type,promise,reason)=>{
     2     console.error(type,promise,reason);
     3     // setImmediate(()=> process.exit(1));
     4 });
     5 
     6 function main(){
     7     return  new Promise((resole, reject) => {
     8         reject('First reject');
     9         reject('Swallowed reject');
    10     });
    11 }
    12 main().then(console.log,console.log);
    13 //打印结果
    14 //multipleResolves事件被触发:reject Promise { <rejected> 'First reject' } Swallowed reject
    15 //then的拒绝受理:First reject

    第三种情况:解决又拒绝,即在Promise构造中一个逻辑下出现先调用了resole又在后面调用了reject,以下示例:

     1 process.on('multipleResolves',(type,promise,reason)=>{
     2     console.error(type,promise,reason);
     3 });
     4 
     5 function main(){
     6     return  new Promise((resole, reject) => {
     7         resole("First call");
     8         reject('First reject');
     9     });
    10 }
    11 main().then(console.log,console.log);
    12 //打印结果
    13 //multipleResolves事件被触发:reject Promise { 'First call' } First reject
    14 //then的解决受理:First call

    第四种情况:拒绝又解决:即在Promise构造中一个逻辑下出现了先调用了reject又在后面调用了resole,以下示例:

     1 process.on('multipleResolves',(type,promise,reason)=>{
     2     console.error(type,promise,reason);
     3 });
     4 
     5 function main(){
     6     return  new Promise((resole, reject) => {
     7         reject('First reject');
     8         resole("First call");
     9     });
    10 }
    11 main().then(console.log,console.log);
    12 //打印结果
    13 //multipleResolves事件被触发:resolve Promise { <rejected> 'First reject' } First call
    14 //then的拒绝受理:First reject

    -- rejectionHandled事件:当promise延后调用catch捕获错误时,会触发该事件,在官方文档中的描述是晚一轮

     1 process.on('rejectionHandled',function(promise){
     2     console.log('catch没有及时触发',promise);
     3 });
     4 
     5 let oP = new Promise((resolve, reject) => {
     6     reject(new Error("no"));
     7 });
     8 // oP.catch((err) => {  //同步代码的cathc捕获不会触发rejectionHandled事件
     9 //     console.log("异常捕获:" + err.toString());
    10 // });    
    11 setTimeout(()=>{    //异步导致的延后会触发rejectionHandled事件
    12     oP.catch((err) => {
    13         console.log("异常捕获:",err.toString());
    14     });    
    15 });

    -- unhandledRejection事件:当promise中reject的异常在同步任务中没有使用catch捕获就会触发该事件,即便是在异步情况下使用了catch也会触发该事件(如上面rejectionHandled事件的示例情况)。

     1 // process.on('rejectionHandled',function(promise){
     2 //     console.log('catch没有及时触发');
     3 // });
     4 process.on('unhandledRejection',function(reason, promise){
     5     console.log("---------------");
     6 });
     7 
     8 let op = new Promise((resolve,reject)=>{
     9     reject(new Error("no"));
    10 });
    11 // setTimeout(()=>{
    12 //     op.catch((err)=>{
    13 //         console.log('异常捕获:');
    14 //     })
    15 // })

    2.6监听未捕获异常的一些事件:

    -- uncaughtExceptionMonitor:当进程上抛出异常而没有被捕获时触发该事件。

    -- uncaughtException:当进程上抛出异常而没有被捕获时触发该事件,并且使异常静默。

    需要注意的是异步任务中的异常同样可以被捕获,但是Pormise中未捕获的异常不能触发这两个事件,Pormise的未捕获异常由前面介绍的rejectionHandled和unhandledRejection监听。

     1 process.on('uncaughtExceptionMonitor',function(err, origin){
     2     console.log("监听到当前进程上出现未捕获的异常");
     3 });
     4 process.on('uncaughtException',function(err, origin){
     5     console.log('监听到当前进程上出现未捕获的异常,并静默该异常');  //静默异常表示被监听到的异常不会被抛出
     6 });
     7 function fu(){
     8     throw new Error('fu');
     9 }
    10 // setTimeout(()=>{
    11 //     fu();
    12 // });
    13 fu();
    14 
    15 //当异常被捕获,则uncaughtExceptionMonitor 、uncaughtException事件不会被触发
    16 // try{
    17 //     fu();
    18 // }catch(err){
    19 //     console.log(err.toString());
    20 // }

    关于异常还有一个方法:process.setUncaughtExceptionCaptureCallback(fn),这个方法的功能与uncaughtException一致,并且会导致uncaughtException事件不会被触发。这个方法的使用方式就是传入一个回调函数,这个回调函数接收到错误对象作为参数。它同样具有静默异常的功能。

     1 process.setUncaughtExceptionCaptureCallback(function(err){
     2     console.log('---------------');
     3     console.log(err.toString());
     4 });
     5 process.on('uncaughtExceptionMonitor',function(err, origin){
     6     console.log("监听到当前进程上出现未捕获的异常");
     7 });
     8 process.on('uncaughtException',function(err, origin){
     9     console.log('监听到当前进程上出现未捕获的异常,并静默该异常');  //静默异常表示被监听到的异常不会被抛出
    10 });
    11 function fu(){
    12     throw new Error('fu');
    13 }
    14 fu();
    View Code

    并且还可以通过process.hasUncaughtExceptionCaptureCallback()方法来检测当前是否使用process.setUncaughtExceptionCaptureCallback(fn)方法,该方法返回一个boolean值。

    2.7监听进程警告的事件和触发警告的方法:warning、emitwarning

     1 process.on('warning',function(warning){    //监听警告
     2     console.log('进程警告:');
     3     console.log('名称:' + warning.name);
     4     console.log('信息:' + warning.message);
     5     console.log('堆栈:' + warning.stack);
     6 });
     7 process.emitWarning('Something happened!',{    //触发警告
     8     type:'第一个警告',
     9     code:'MY_WARNING',
    10     detail:'This is some additional in formation'
    11 });

    触发警告的方法有三种参数形式:

    process.emitWarning(warning[, options])
    process.emitWarning(warning[, type[, code]][, ctor])
    process.emitWarning(Error);

    2.8创建独立线程时触发worker事件,详细在后面会有专门的博客解析关于worker模块的内容。

    2.9在当前js任务堆栈后,事件轮询前添加一个堆栈任务:

    -- process.nextTick(callback[, ...args]);

     1 console.log('start');
     2 process.nextTick(function(){
     3     console.log('nextTick callback');
     4 });
     5 setTimeout(function(){
     6     console.log('setTimeout');
     7 });
     8 console.log('scheduled');
     9 // start
    10 // scheduled
    11 // nextTick callback
    12 // setTimeout

    注意的是如果在process.nextTick内部添加process.nextTick会导致死循环,在异步堆栈上同样可以使用:

     1 console.log('start');
     2 process.nextTick(function(){
     3     console.log('nextTick callback1');
     4 });
     5 setTimeout(function(){
     6     console.log('setTimeout1');
     7     process.nextTick(function(){
     8         console.log('nextTick callback2');
     9     });
    10     console.log('setTimeout2');
    11 });
    12 console.log('scheduled');
    13 // start
    14 // scheduled
    15 // nextTick callback1
    16 // setTimeout1
    17 // setTimeout2
    18 // nextTick callback2

    -- queueMicrotask():这是全局上的一个实现添加堆栈的方法,这个方法使用来替代process.nextTick方法的,但需要注意它与process.nextTick、Promise堆栈的执行顺序。

     1 setTimeout(()=>{
     2     console.log('4');
     3 });
     4 console.log('a');
     5 Promise.resolve().then(() => console.log(2));
     6 console.log('b');
     7 queueMicrotask(() => console.log(3));
     8 console.log('c');
     9 process.nextTick(() => console.log(1));
    10 console.log('d');
    11 //a b c d 1 2 3 4

    但是queueMicrotask()只能接收一个回调函数,不能像process.nextTick那样直接在后面添加参数,为了解决这个问题参考下面这个来自官方的示例:

     1 function deferred(a, b) {
     2   console.log('microtask', a + b);
     3 }
     4 console.log('start');
     5 queueMicrotask(deferred.bind(undefined, 1, 2));
     6 console.log('scheduled');
     7 // 输出:
     8 // start
     9 // scheduled
    10 // microtask 3

    2.10关于进程上的流相关API的应用,可以参考基于node实现一个简单的脚手架工具(node控制台交互项目),后面会有关于流更详细的解析博客。

    process上流的API有:

    process.stderr
    process.stderr.fd
    process.stdin
    process.stdin.fd
    process.stdout
    process.stdout.fd
    
    //通过控制台输入流的API
    process.stdin.resume();
    1 #!/usr/bin/env node
    2 
    3 process.stdout.write('\033[33m输入:\033[39');
    4 process.stdin.resume(); //等待输入
    5 process.stdin.setEncoding('utf-8');
    6 process.stdin.on('data',function(data){
    7     process.stdin.pause();
    8     console.log('\033[90m输入的内容是:' + data + '\033[39m');
    9 })
    这是来自手脚那篇博客的实例应用代码

    2.11与IPC通道相关的API:

    还记得在前面message事件中讲过进程之间的通信,node进程通信就是基于IPC通道,但这里不作详细的解释,后面的node进程管理会有详细的解析,这里只看在Process上提供的API。

    -- process.channel:IPC通道的衍生,是对子进程IPC通道的引用。在主进程上没有该属性所以返回值为undefined。

    -- process.connected:改属性表示当前进程的IPC通道是否建立连接,如果连接建立了就返回true,否则返回false。但如果当前进程没有启动IPC通道则返回undefiend。
    -- process.kill(pid):用来杀死指定进程,如果指定的进程pid不存在则会报错,官方文档中说可以传入第二个参数作为信号事件,但测试第二个参数就报错。

    2.12当前进程诊断报告的相关API

     1 process.report:管理诊断报告的对象;
     2 process.report.compact:用于设置诊断包括是否以JSON格式,改属性值类型<Boolean>,默认false;
     3 process.report.directory:用于设置保存诊断报告的路径,默认值为空,表示将报告写入工作目录;
     4 process.report.filename:写入报告的文件名。 如果设置为空字符串,则输出文件名将由时间戳、PID 和序列号组成。 默认值为空字符串;
     5 process.report.getReport([err]):返回正在运行的进程的诊断报告的 JavaScript 对象表示形式。 报告的 JavaScript 堆栈跟踪取自 err(如果存在)。
     6 process.report.reportOnFatalError:如果为 true,则会生成有关致命错误(例如内存不足错误或 C++ 断言失败)的诊断报告。
     7 process.report.reportOnSignal:如果为 true,则当进程接收到 process.report.signal 指定的信号时生成诊断报告。
     8 process.report.reportOnUncaughtException:如果为 true,则针对未捕获的异常生成诊断报告。
     9 process.report.signal:用于触发诊断报告创建的信号。 默认为 'SIGUSR2'。
    10 process.report.writeReport([filename][, err]):将诊断报告写入文件。 如果未提供 filename,则默认文件名包括日期、时间、PID 和序列号。 报告的 JavaScript 堆栈跟踪取自 err(如果存在)。

    测试生成诊断报告:

    process.report.reportOnUncaughtException = true;
    throw new Error('诊断报告');
  • 相关阅读:
    ios开发遇到的问题
    getopt()——命令行参数分析
    浅谈Samsung Exynos4412处理器
    TTL电平,CMOS电平,232/485电平,OC门,OD门基础知识
    (转载)跟Classic ARM 处理器说拜拜——Atmel SAMA5D3 Xplained开发板评测
    (转载)Quartus II中FPGA的管脚分配保存方法(Quartus II)
    DE2资源集锦
    收到DE2+LCM+ D5M套件,拾回DE2,努力,奋进!
    windows 服务器时间同步失败处理方法
    机械加工仿真软件-----三维弯管机仿真系统
  • 原文地址:https://www.cnblogs.com/ZheOneAndOnly/p/15946896.html
Copyright © 2020-2023  润新知