nodejs学习笔记01-基础认知

node.js 基本命令,不同系统安装,语法学习

1. 基础认知

Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境

  • 也就是说Node.js基于V8引擎来执行JavaScript的代码,但是不仅仅只有V8引擎:
    • V8引擎可以嵌入到任何C ++应用程序中,无论是Chrome还是Node.js,事实上都是嵌入了V8引擎来执行JavaScript代码;
    • 但是在Chrome浏览器中,还需要解析、渲染HTML、CSS等相关渲染引擎,另外还需要提供支持浏览器操作 的API、浏览器自己的事件循环等;
    • 另外,在Node.js中我们也需要进行一些额外的操作,比如文件系统读/写、网络IO、加密、压缩解压文件等操作;

1.1. Node.js vs 浏览器

1.2. Node.js架构

  • 编写的JavaScript代码会经过V8引擎,再通过Node.js的Bindings,将任务放到Libuv的事件循环中;
  • libuv(Unicorn Velociraptor—独角伶盗龙)是使用C语言编写的库;
  • libuv提供了事件循环、文件系统读写、网络IO、线程池等等内容;

1.3. Node.js的应用场景

Node.js的快速发展也让企业对Node.js技术越来越重视,在前端招聘中通常会对Node.js有一定的要求,特别对于高级前端开发工程师,Node.js更是必不可少的技能

  • 目前前端开发的库都是以node包的形式进行管理;
  • npm、yarn工具成为前端开发使用最多的工具;
  • 越来越多的公司使用Node.js作为web服务器开发;
  • 大量项目需要借助Node.js完成前后端渲染的同构应用;
  • 资深前端工程师需要为项目编写脚本工具(前端工程师编写脚本通常会使用JavaScript,而不是Python或者shell);
  • 很多企业在使用Electron来开发桌面应用程序; – VSCode基于Electron开发,Electron基于node开发

1.4. Node.js的安装

  • Node.js是在2009年诞生的,版本分别是LTS 以及Current:

    • LTS版本:相对稳定一些,推荐线上环境使用该版本;
    • Current版本:最新的Node版本,包含很多新特性;

  • 这些我们选择什么版本呢?

    • 如果是学习使用,可以选择current版本;

    • 如果是公司开发,建议选择LTS版本;

  • Node的安装方式有很多:

    • 可以借助于一些操作系统上的软件管理工具,比如Mac上的homebrew,Linux上的yum、dnf等;
    • 也可以直接下载对应的安装包下载安装;

  • 选择下载安装,下载自己操作系统的安装包直接安装就可以了:

    • window选择.msi安装包,Mac选择.pkg安装包,Linux选择.tar.xz;
    • 安装过程中会配置环境变量;并且会安装npm(Node Package Manager)工具;

1.5. Node的版本工具

  • 在实际开发学习中,只需要使用一个Node版本来开发或者学习即可
  • 但是,如果你希望通过可以快速更新或切换多个版本时,可以借助于一些工具:
    • nvm:Node Version Manager;
    • n:Interactively Manage Your Node.js Versions(交互式管理你的Node.js版本)

  • 问题:这两个工具都不支持window
    • n:n is not supported natively on Windows.
    • nvm:nvm does not support Windows

2. 安装

2.1. Linux安装node

2.1.1. 下载安装包

http://nodejs.cn/download/

下载对应 linux 版本

2.1.2. 服务器新建文件

1
2
3
[root@centos7 ~]# cd /
[root@centos7 /]# cd app
[root@centos7 app]# mkdir node

利用transmit把下载的文件放到node文件夹下

2.1.3. 解压文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@centos7 app]# cd node
[root@centos7 node]#
[root@centos7 node]# ls -l
总用量 21516
-rw-r--r-- 1 root root 22031988 6月 1 13:11 node-v16.15.0-linux-x64.tar.xz
[root@centos7 node]# xz -d node-v16.15.0-linux-x64.tar.xz
[root@centos7 node]#
[root@centos7 node]# ls -l
总用量 94036
-rw-r--r-- 1 root root 97576960 6月 1 13:11 node-v16.15.0-linux-x64.tar
[root@centos7 node]#
[root@centos7 node]# tar xvf node-v16.15.0-linux-x64.tar
[root@centos7 node]# ls -l
总用量 94040
drwxr-xr-x 6 1001 1001 4096 4月 27 06:15 node-v16.15.0-linux-x64
-rw-r--r-- 1 root root 97576960 6月 1 13:11 node-v16.15.0-linux-x64.tar
[root@centos7 node]#

2.1.4. 配置环境

1
2
[root@centos7 node]# cd ~
[root@centos7 ~]# vi .bash_profile

加入node命名

1
2
3
4
PATH=$PATH:$HOME/bin
export JAVA_HOME=/app/java/jdk1.8.0_311
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin:/app/node/node-v16.15.0-linux-x64/bin

使其生效

1
[root@centos7 ~]# source ~/.bash_profile

现在可以用命令

1
2
3
[root@centos7 ~]# node -v
v16.15.0
[root@centos7 ~]#

2.2. nodejs服务后台持续运行

forever是一个nodejs守护进程,完全由命令行操控。forever会监控nodejs服务,并在服务挂掉后进行重启。

###安装 forever

npm install forever -g

2.2.1. 使用 forever 启动 js 文件

forever start index.js

2.2.2. 停止 js 文件

forever stop index.js

2.2.3. 启动js文件并输出日志文件

forever start -l forever.log -o out.log -e err.log index.js

2.2.4. 重启js文件

forever restart index.js

2.2.5. 查看正在运行的进程

forever list

2.3. macos安装nodejs

http://nodejs.cn/download/

下载对应 macos 版本,点击解压安装

This package has installed:
    •	Node.js v16.15.0 to /usr/local/bin/node
    •	npm v8.5.5 to /usr/local/bin/npm
Make sure that /usr/local/bin is in your $PATH.

2.4. 版本管理工具-n

https://github.com/tj/n

  • 安装n:直接使用npm安装即可

    1
    2
    3
    4
    5
    # 安装工具n
    npm install n -g

    # 查看安装的版本
    n --version

  • 安装最新的lts版本:

    • 可以两个版本都安装

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # 安装最新的lts版本
      sudo n lts

      # 安装最新的版本
      sudo n latest

      # 安装指定版本
      sudo n 10.16.0

      # 查看所有版本
      sudo n

3. JavaScript代码执行

如果编写一个index.js文件,里面存放JavaScript代码,如何来执行它呢?

  • 目前我们知道有两种方式可以执行:

    • 将代码交给浏览器执行;
    • 将代码载入到node环境中执行;
  • 如果把代码交给浏览器执行:

    • 需要通过让浏览器加载、解析html代码,所以需要创建一个html文件;
    • 在html中通过script标签,引入js文件;
    • 当浏览器遇到script标签时,就会根据src加载、执行JavaScript代码;
    • <script src="index.js"></script>
  • 如果希望把js文件交给node执行:

    • 首先电脑上需要安装Node.js环境,安装过程中会自动配置环境变量;
    • 可以通过终端命令node js文件的方式来载入和执行对应的js文件;
    • node index.js

4. Node的REPL

REPL - Read-Eval-Print Loop 的简称,翻译为“读取-求值-输出”循环;是一个简单的、交互式的编程环境;

事实上,我们浏览器的console就可以看成一个REPL

Node也给我们提供了一个REPL环境,可以在其中演练简单的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ node
Welcome to Node.js v16.15.0.
Type ".help" for more information.
> let a = 10;
undefined
> let b = 2;
undefined
> let c = a/b;
undefined
> console.log(c);
5
> process
process {
version: 'v16.15.0',
versions: {
node: '16.15.0',
v8: '9.4.146.24-node.20',
uv: '1.43.0',
zlib: '1.2.11',
brotli: '1.0.9',
ares: '1.18.1',
modules: '93',
nghttp2: '1.47.0',
napi: '8',
llhttp: '6.0.4',
openssl: '1.1.1n+quic',
cldr: '40.0',
icu: '70.1',
tz: '2021a3',
unicode: '14.0',
ngtcp2: '0.1.0-DEV',
nghttp3: '0.1.0-DEV'
},
...
}
> .exit

5. Node程序传递参数

正常情况下执行一个node程序,直接跟上对应的文件即可: node index.js

在某些情况下执行node程序的过程中,我们可能希望给node传递一些参数: node index.js env=development test

如何在程序中获取到传递的参数?

  • 获取参数其实是在process的内置对象中的;
  • console.log(process.argv); 返回的是一个数组

5.1. 为什么叫argv呢?

在C/C++程序中的main函数中,实际上可以获取到两个参数:

  1. argc:argument counter的缩写,传递参数的个数;

  2. argv:argument vector的缩写,传入的具体参数

    • vector翻译过来是矢量的意思,在程序中表示的是一种数据结构

    • 在C++、Java中都有这种数据结构,是一种数组结构

    • 在JavaScript中也是一个数组,里面存储一些参数信息

遍历参数

1
2
3
process.argv.forEach(item=>{
console.log(item);
})

6. Node的输出

7. 全局对象

https://nodejs.org/dist/latest-v16.x/docs/api/globals.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
-- Global objects
Class: AbortController
abortController.abort([reason])
abortController.signal
Class: AbortSignal
Static method: AbortSignal.abort([reason])
Static method: AbortSignal.timeout(delay)
Event: 'abort'
abortSignal.aborted
abortSignal.onabort
abortSignal.reason
Class: Buffer
__dirname
__filename
atob(data)
btoa(data)
clearImmediate(immediateObject)
clearInterval(intervalObject)
clearTimeout(timeoutObject)
console
Crypto
crypto
CryptoKey
Event
EventTarget
exports
fetch
Class FormData
global
Class Headers
MessageChannel
MessageEvent
MessagePort
module
performance
process
queueMicrotask(callback)
require()
Response
Request
setImmediate(callback[, ...args])
setInterval(callback, delay[, ...args])
setTimeout(callback, delay[, ...args])
SubtleCrypto
TextDecoder
TextEncoder
URL
URLSearchParams
WebAssembly

7.1. 特殊的全局对象

为什么称之为特殊的全局对象呢?

  1. 这些全局对象可以在模块中任意使用,但是在命令行交互中是不可以使用的;
  2. 包括:__dirname、__filename、exports、module、require()

__dirname:获取当前文件所在的路径:

​ 注意:不包括后面的文件名

__filename:获取当前文件所在的路径和文件名称:

​ 注意:包括后面的文件名称

7.2. 常见的全局对象

  • process对象:process提供了Node进程中相关的信息:
    • 比如Node的运行环境、参数信息等;
  • console对象:提供了简单的调试控制台:

  • 定时器函数:在Node中使用定时器有好几种方式:
    • setTimeout(callback, delay[, …args]):callback在delay毫秒后执行一次;
    • setInterval(callback, delay[, …args]):callback每delay毫秒重复执行一次;
    • setImmediate(callback[, …args]):callbackI / O事件后的回调的“立即”执行;
    • process.nextTick(callback[, …args]):添加到下一次tick队列中;

7.3. global对象

global是一个全局对象

在控制台输入 global. 按下Tab键,得到以下内容

可见 process、console、setTimeout等都有被放到global中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
LearningtekiMacBook-Air:node-demo Learning$ node
Welcome to Node.js v16.15.0.
Type ".help" for more information.
> global.
global.__proto__ global.hasOwnProperty global.isPrototypeOf global.propertyIsEnumerable global.toLocaleString
global.toString global.valueOf

global.constructor

global.AbortController global.AbortSignal global.AggregateError global.Array global.ArrayBuffer
global.Atomics global.BigInt global.BigInt64Array global.BigUint64Array global.Boolean
global.Buffer global.DataView global.Date global.Error global.EvalError
global.Event global.EventTarget global.FinalizationRegistry global.Float32Array global.Float64Array
global.Function global.Infinity global.Int16Array global.Int32Array global.Int8Array
global.Intl global.JSON global.Map global.Math global.MessageChannel
global.MessageEvent global.MessagePort global.NaN global.Number global.Object
global.Promise global.Proxy global.RangeError global.ReferenceError global.Reflect
global.RegExp global.Set global.SharedArrayBuffer global.String global.Symbol
global.SyntaxError global.TextDecoder global.TextEncoder global.TypeError global.URIError
global.URL global.URLSearchParams global.Uint16Array global.Uint32Array global.Uint8Array
global.Uint8ClampedArray global.WeakMap global.WeakRef global.WeakSet global.WebAssembly
global._ global._error global.assert global.async_hooks global.atob
global.btoa global.buffer global.child_process global.clearImmediate global.clearInterval
global.clearTimeout global.cluster global.console global.constants global.crypto
global.decodeURI global.decodeURIComponent global.dgram global.diagnostics_channel global.dns
global.domain global.encodeURI global.encodeURIComponent global.escape global.eval
global.events global.fs global.global global.globalThis global.http
global.http2 global.https global.inspector global.isFinite global.isNaN
global.module global.net global.os global.parseFloat global.parseInt
global.path global.perf_hooks global.performance global.process global.punycode
global.querystring global.queueMicrotask global.readline global.repl global.require
global.setImmediate global.setInterval global.setTimeout global.stream global.string_decoder
global.sys global.timers global.tls global.trace_events global.tty
global.undefined global.unescape global.url global.util global.v8
global.vm global.wasi global.worker_threads global.zlib

>

7.4. global vs window

在浏览器中,全局变量都是在window上的,比如有document、setInterval、setTimeout、alert、console等等

在Node中,我们也有一个global属性,并且看起来它里面有很多其他对象

但是在浏览器中执行的JavaScript代码,如果我们在顶级范围内通过var定义的一个属性,默认会被添加window 对象上:

1
2
3
var name = 'window';
// window
console.log(window.name);

但是在node中,我们通过var定义一个变量,它只是在当前模块中有一个变量,不会放到全局中:

因为浏览器中没有模块的概念,js文件代码通过script标签被引入到html中,被js引擎解释执行,多个js文件代码会被依次根据引入顺序加载,某个js文件定义的var变量可被该js文件引入顺序以后的js所使用,定义的var变量放在顶部范围是可以的;

但是node是将每个js文件当做每个模块,其中定义的变量属于该模块而不能属于顶级范围,各个js通过暴露变量exports.name 来让其他文件调取name值,其他文件通过require(js文件路径)来获取该文件中name的值

1
2
3
var name = 'window';
// undefined
console.log(global.name);

为什么process可以放入自定义argv参数?

https://github.com/nodejs/node/blob/main/lib/internal/bootstrap/node.js

node内部中设置了process变量,也实现了argv数组,定义了argv[0]和argv[1]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ObjectDefineProperty(globalThis, 'process', {
__proto__: null,
get() {
return _process;
},
set(value) {
_process = value;
},
enumerable: false,
configurable: true,
});


// 同目录下的pre_execution.js中
process.argv[0] = process.execPath;
process.argv[1] = path.resolve(process.argv[1]);
本文结束  感谢您的阅读