下面先容利用 Chrome DevTools 调试的方法,首先安装 Chrome Extension NIM,打开 Inspect 入口页面 chrome://inspect
写一个大略 debug.js 测试文件:
// apiTest/debug.js console.log(\"大众this is debug test\公众)function test () { console.log(\公众hello world\"大众)}test()
利用node --inspect-brk来启动脚本,-brk相称于在程序入口前加一个断点,使得程序会在实行前停下来

$ node --inspect-brk apiTest/debug.js Debugger listening on ws://127.0.0.1:9229/44b5d11e-3261-4090-a18c-2d811486fd0aFor help, see: https://nodejs.org/en/docs/inspector
在 chrome://inspect 中设置监听端口 9229(默认),就可以看到可以 debug 的页面:
(function (exports, require, module, __filename, __dirname) { console.log(\公众this is debug test\公众)function test () { console.log(\公众hello world\"大众)}test()});
如果我们利用node --inspect来启动脚本,那全体代码直接运行到代码结尾,无法进行调试,但此时 Node 还进程没有结束,以是可以在 http://127.0.0.1:9229/json/list 查询 devtoolsFrontendUrl ,复制此 Url 到 Chrome 上进行调试。
看到利用 Chrome DevTools 的调试方法还是比较繁芜的,一些 IDE 都支持直接断点调试,推举WebStorm、VScode。
二、全局变量在 Node 中常用的全局方法有 CommonJS、Buffer、process、console、timer 等,这些方法不须要 require引入 API 就可以直策应用。
如果希望有属性或方法可以“全局利用”,那就将它挂载在 Node 的global工具上:
global.gNum = 300console.log(gNum); // 300
在 Node 中所有模块都可以利用这些全局变量,以下就先容 Node 中的全局变量
2.1 CommonJS 模块
Node CommonJS 模块规范根据实现了module、exports和require模块机制。Node 对每个文件都被进行了模块封装,每个模块有自己的浸染域,如在 debug 时看到的:
(function (exports, require, module, __filename, __dirname) { // some code});
模块机制中的 __dirname、__filename、exports、module、require()这些变量虽然看起来是全局的,但实在它们仅存在于模块范围。须要把稳的几点是:
模块内部module变量代表模块本身模块供应require()方法引入外部模块到当前的高下文中module.exports属性代表模块对外接口,默认的快捷办法exports大略的利用办法如下:
/ common_exports.js /exports.num = 100 exports.obj = { a : 200}exports = { count : 300}/ common_require.js /const mod = require('./common_exports')console.log(mod) // { num: 100, obj: { a: 200 } }console.log(mod.count) // undefined
把稳到上例中的mod.count为undefined,这是由于exports只是module.exports的引用,可以给exports添加属性,但不能修正exports的指向。
2.2 process 进程工具
process 包含了进程干系的属性和方法,Node 的 process 文档 中的内容特殊多,列举几个常用方法。
Node 进程启动时通报的参数都在 process.arg数组中:
// process.jsconst {argv , execPath} = processargv.forEach((val, index) => { console.log(`${index}: ${val}`)})console.log(execPath)
可以在实行 process.js 时通报其他参数,这些参数都会保存在argv中:
$ node apiTest/process.js one=1 --inspect --version0: /usr/local/bin/node1: /Users/mobike/Documents/webProjects/testNode/apiTest/process.js2: one=13: --inspect4: --version/usr/local/bin/node
process.argv第一个参数便是 process.execPath ,即调用实行程序 Node 的路径,第二个参数时被实行的 JS 文件路径,剩下的便是自定义参数。
process.env是包含运行环境各种参数的工具,可以直接输出env查看所有参数信息,也可以输出某个属性:
const {env} = process.envconsole.log(env.PATH) // /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/Documents/webProjects/testNode/node_modules/.binconsole.log(env.SHELL) // /bin/zsh
在 webpack 打包过程中常用process.env.NODE_ENV判断生产环境或开拓环境,process.env是没有NODE_ENV这个属性的,你可以在系统环境变量中配置,也可以在项目程序直接设置process.env.NODE_ENV=‘dev’。
process.cwd()方法返回 Node.js 进程确当前事情目录,和 Linus 命令$ pwd功能一样:
// process.jsconsole.log(process.cwd()) // /Users/Documents/webProjects/testNode复制代码$ node process.js/Users/WebstormProjects/testNode$ pwd/Users/WebstormProjects/testNode
2.3 Timers 异步
Node 中的计时器方法与 Web 浏览器中的JS 计时器类似,但内部实现是基于 Node 的 Event Loop。Node 中的计时器有setImmediate()、setTimeout()、setInterval()。
在 Node 中有一个轻量级的process.nextTick()异步方法,它是在当前事宜行列步队结束时调用, setImmediate()是当前 Node Event Loop 结束时立即实行,那实行顺序有什么差异呢?
下面举例解释process.nextTick(fn)与setImmediate(fn)与setTimeout(fn,0)之间的差异:
// timer.js setImmediate(()=>{ console.log(\"大众setImmediate\"大众)});setTimeout(()=>{ console.log(\公众setTimeout 0\"大众)},0);setTimeout(()=>{ console.log(\"大众setTimeout 100\"大众)},100);process.nextTick(()=>{ console.log(\公众nextTick\公众) process.nextTick(()=>{ console.log(\"大众nextTick inner\"大众) })});
看下实行结果:
$ node timer.js nextTicknextTick innersetTimeout 0setImmediatesetTimeout 100
process.nextTick()中的回调函数最快实行,由于它将异步事宜插入到当前实行行列步队的末端,但如果process.nextTick()中的事宜实行韶光过长,后面的异步事宜就被延迟。
setImmediate()实行最慢,由于它将事宜插入到下一个事宜行列步队的队首,不会影响当前事宜行列步队的实行。当setTimeout(fn, 0)是在setImmediate()之前实行。
2.4 Buffer 二进制
Buffer 工具用于处理二进制数据流。JS 没有处理二进制的功能,而 Node 中的一部分代码是由 C++ 实现的,所有 Node 中的 Buffer 性能部分用 C++ 实现,非性能部分由 JS 封装。
Buffer 实例类似整数数组,元素为十六进制的两位数(0~255),并且挂载在 global 工具上不须要 require就能利用。
最新的 Buffer API 利用Buffer.alloc(length, value)创建固定长度为 length 的 Buffer 实例,value 默认添补 0,利用Buffer.from()将其它类型数据转为 Buffer:
console.log(Buffer.alloc(5)) // <Buffer 00 00 00 00 00>console.log(Buffer.alloc(5, 44)) // <Buffer 2c 2c 2c 2c 2c>console.log(Buffer.from([3, 4, 5])) // <Buffer 03 04 05>console.log(Buffer.from('test')) // <Buffer 74 65 73 74>console.log(Buffer.from('测试')) // <Buffer e6 b5 8b e8 af 95>
把稳到字符串转 Buffer 时英文占一位,中文占三位,而不是四位,当中文乱码的时可以考虑没有精确读取 Buffer 流。
Buffer 类供应几个静态方法,Buffer.byteLength()打算长度,Buffer.isBuffer()做验证,Buffer.concat()拼接 Buffer 实例:
const buf1 = Buffer.from([3, 4, 5])const buf2 = Buffer.from('test')console.log(Buffer.byteLength('test')) // 4console.log(Buffer.byteLength('测试')) // 6 console.log(Buffer.isBuffer('test')) // falseconsole.log(Buffer.isBuffer(buf1)) // trueconsole.log(Buffer.concat([buf1, buf2])) // <Buffer 03 04 05 74 65 73 74>
除此之外,Buffer 实例也有常用的属性和方法,类似 JS 中的 String,有length、toString('base64')、equals()、indexOf()等。
三、根本 API3.1 path 路径干系
path 是处理和路径干系问题的内置 API,可以直接require('path')利用。以下示例常用的 path 方法。
对路径的处理常用path.normalize()规范路径、path.join()拼接路径,以及利用path.resolve()将相对路径解析为绝对路径:
const path = require('path')console.log( path.normalize('//asd\/das'), // /asd/das path.join('user', 'local'), // user/local path.resolve('./')) // /Users/Documents/webProjects/testNode/apiTest
解析某个路径,可以用path.basename()得到文件名称,path.extname()得到后缀扩展名,path.dirname()得到目录名:
const path = require('path')const filePath = 'webProjects/testNode/apiTest/path.js'console.log( path.basename(filePath), // path.js path.extname(filePath) // .js path.dirname(filePath), // webProjects/testNode/apiTest)
以上解析路径方法得到某个值,还可以利用path.parse()完备解析路径为一个工具,path.format()反向操作:
let sp = path.parse(filePath)console.log(sp)// { root: '',// dir: 'webProjects/testNode/apiTest',// base: 'path.js',// ext: '.js',// name: 'path' }console.log(path.format(sp))// webProjects/testNode/apiTest/path.js
除此之外,还有对付系统路径的操作,利用path.sep取得路径分隔符,路径片段分隔符,POSIX 上是/, Windows 上是\,path.delimiter取得系统路径定界符,POSIX 上是:,Windows 上是;,示例如下:
console.log(filePath.split(path.sep)) // [ 'webProjects', 'testNode', 'apiTest', 'path.js' ]console.log(process.env.PATH) // 系统路径配置// /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbinconsole.log(process.env.PATH.split(path.delimiter))// [ '/usr/local/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin' ]
以上便是 Node 对路径的常用操作,须要把稳的是,在获取路径时有几种办法,得到的路径是不同的:
__dirname 、__filename:总是返回文件绝对路径;process.cwd() 或 $ pwd :返回实行 Node 命令的文件夹;path.resolve('./'):是相对 Node 启动文件夹,在require()中./是相对付当前文件夹;3.2 events 事宜
大部分 Node API 都采取异步事宜驱动,所有能触发事宜工具都是 EventEmitter 类的实例,通过 EventEmitter.on()绑定事宜,然后通过 EventEmitter.emit() 触发事宜。
// apiTest/events.jsconst Events = require('events')class MyEvents extends Events{}const event = new MyEvents()event.on('test-event',()=>{ console.log('this is an event')})event.emit('test-event')setInterval(()=>{ event.emit('test-event')},500)
实行以上代码会一贯连续惩罚 test-event 事宜,当然还可以通报事宜参数,并且可以通报多个参数。修正上诉代码如下:
event.on('test-event', (data, time) => { console.log(data,time)})event.emit('test-event', [1, 2, 3], new Date())$ node apiTest/events.js[ 1, 2, 3 ] 2019-04-23T07:28:00.420Z
同一个事宜监听器可以绑定多个事宜,触发时按照绑定顺序加入实行行列步队,并且可以利用EventEmitter.removeListener()删除监听器的事宜:
function fn1 () { console.log('fn1')}function fn2 () { console.log('fn2')}event.on('multi-event',fn1)event.on('multi-event',fn2)setInterval(()=>{ event.emit('multi-event')},500)setTimeout(()=>{ event.removeListener('multi-event', fn2)}, 600)$ node apiTest/events.js[ 1, 2, 3 ] 2019-04-23T07:39:11.624Zfn1fn2fn1fn1...
3.3 fs 文件系统
Node 文件模块通过require('fs)利用,所用方法都有同步和异步方法。
文件系统中的异步方法,第一个参数保留给非常,操作成功时参数值为null或undefined,末了一个参数便是回调函数。例如读取文件的fs.readFile()和写文件的fs.writeFile()示例如下:
const fs = require('fs')fs.readFile('./apiTest/fs.js', (err, data) => { if (err) throw err console.log('readFile done!!!')})fs.writeFile('./apiTest/fs.txt', 'this is test file', { encoding: 'utf8'}, (err) => { if (err) throw err console.log('writeFile done!!!')})小结
加油呢少年~