Node.js

什么是Node.js呢?

我们先看一下官方对 Node.js 的定义:
   Node.js 是一个基于 V8 JavaScript 引擎的 JavaScript 运行时环境。
 
 
但是这句话对于很多同学来说,非常笼统:
 
什么是 JavaScript 运行环境?
 
为什么 JavaScript 需要特别的运行环境呢?
 
什么又是 JavaScript 引擎?
 
什么是 V8
  我们先来把这些概念搞清楚,再去看 Node 到底是什么?

 JavaScript无处不在

 
Stack Overflow 的创立者之一 Jeff Atwood 2007 年提出了著名的 Atwood 定律
Any application that can be written in JavaScript, will eventually be written in JavaScript.
 
任何可以使用 JavaScript 来实现的应用 都最终都会 使用 JavaScript 实现
  
 

浏览器内核是什么?

大家有没有深入思考过: JavaScript 代码,在浏览器中是如何被执行的?
  我们经常会说:不同的浏览器有不同的内核组成
 
Gecko :早期被 Netscape Mozilla Firefox 浏览器使用;
 
Trident :微软开发,被 IE4~IE11 浏览器使用,但是 Edge 浏览器已经转向 Blink
 
Webkit :苹果基于 KHTML 开发、开源的,用于 Safari Google Chrome 之前也在使用;
 
Blink :是 Webkit 的一个分支, Google 开发,目前应用于 Google Chrome Edge Opera 等;
 
等等 ...
  事实上,我们经常说的浏览器内核指的是浏览器的排版引擎:
  排版引擎( layout engine ),也称为浏览器引擎( browser engine )、页面渲染引擎( rendering engine ) 或
样版引擎。

 

渲染引擎工作的过程

但是在这个执行过程中, HTML 解析的时候遇到了 JavaScript 标签,应该怎么办呢?
  会停止解析 HTML ,而去加载和执行 JavaScript 代码;
  当然,为什么不直接异步去加载执行 JavaScript 代码,而要在这里停止掉呢?
 
这是因为 JavaScript 代码可以操作我们的 DOM
 
所以浏览器希望将 HTML 解析的 DOM JavaScript 操作之后的 DOM 放到一起来生成最终的 DOM 树,而不是
频繁的去生成新的 DOM 树;
  那么, JavaScript 代码由谁来执行呢?
  JavaScript 引擎

JavaScript引擎

 
为什么需要 JavaScript 引擎呢?
 
事实上我们编写的 JavaScript 无论你交给浏览器或者 Node 执行,最后都是需要被 CPU 执行的;
 
但是 CPU 只认识自己的指令集,实际上是机器语言,才能被 CPU 所执行;
 
所以我们需要 JavaScript 引擎帮助我们将 JavaScript 代码翻译成 CPU 指令来执行;
  比较常见的 JavaScript 引擎有哪些呢?
 
SpiderMonkey :第一款 JavaScript 引擎,由 Brendan Eich 开发(也就是 JavaScript 作者);
 
Chakra :微软开发,用于 IT 浏览器;
 
JavaScriptCore WebKit 中的 JavaScript 引擎, Apple 公司开发;
 
V8 Google 开发的强大 JavaScript 引擎,也帮助 Chrome 从众多浏览器中脱颖而出;

WebKit内核

 
这里我们先以 WebKit 为例, WebKit 事实上由两部分组成的:
 
WebCore :负责 HTML 解析、布局、渲染等等相关的工作;
 
JavaScriptCore :解析、执行 JavaScript 代码;
  看到这里,学过小程序的同学有没有感觉非常的熟悉呢?
  在小程序中编写的 JavaScript 代码就是被 JSCore 执行的;

另外一个强大的JavaScript引擎就是V8引擎。

V8引擎

我们来看一下官方对 V8 引擎的定义:
 
V8 是用 C + + 编写的 Google 开源高性能 JavaScript WebAssembly 引擎,它用于 Chrome Node.js 等。
 
它实现 ECMAScript WebAssembly ,并在 Windows 7 或更高版本, macOS 10.12+ 和使用 x64 IA-32
ARM MIPS 处理器的 Linux 系统上运行。
 
V8 可以独立运行,也可以嵌入到任何 C + + 应用程序中。
 

V8引擎的原理

V8 引擎本身的源码非常复杂,大概有超过 100w C + + 代码,但是我们可以简单了解一下它执行 JavaScript 代码的原理:
 
Parse 模块会将 JavaScript 代码转换成 AST (抽象语法树),这是因为解释器并不直接认识 JavaScript 代码;
 
如果函数没有被调用,那么是不会被转换成 AST 的;
 
Parse V8 官方文档: https://v8.dev/blog/scanner
 
Ignition 是一个解释器,会将 AST 转换成 ByteCode (字节码)
 
同时会收集 TurboFan 优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算);
 
如果函数只调用一次, Ignition 会执行解释执行 ByteCode
 
Ignition V8 官方文档: https://v8.dev/blog/ignition-interpreter
 
TurboFan 是一个编译器,可以将字节码编译为 CPU 可以直接执行的机器码;
 
如果一个函数被多次调用,那么就会被标记为热点函数,那么就会经过 TurboFan 转换成优化的机器码,提高代码的执行性能;
 
但是,机器码实际上也会被还原为 ByteCode ,这是因为如果后续执行函数的过程中,类型发生了变化(比如 sum 函数原来执行的是 number 类型,后
来执行变成了 string 类型),之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码;
 
TurboFan V8 官方文档: https://v8.dev/blog/turbofan-jit
 
上面是 JavaScript 代码的执行过程,事实上 V8 的内存回收也是其强大的另外一个原因,不过这里暂时先不展开讨论:
 
Orinoco 模块,负责垃圾回收,将程序中不需要的内存回收;
 
Orinoco V8 官方文档: https://v8.dev/blog/trash-talk

回顾:Node.js是什么

回顾:官方对Node.js的定义:

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

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

浏览器和Node.js架构区别

我们可以简单理解规划出Node.js和浏览器的差异:

Node.js架构

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

Node.js的应用场景

Node.js 的快速发展也让企业对 Node.js 技术越来越重视,在前端招聘中通常会对 Node.js 有一定的要求,特别对于高级前端开发
工程师, Node.js 更是必不可少的技能:
目前前端开发的库都是以 node 包的形式进行管理;
 
npm yarn 工具成为前端开发使用最多的工具;
 
越来越多的公司使用 Node.js 作为 web 服务器开发;
 
大量项目需要借助 Node.js 完成前后端渲染的同构应用;
 
资深前端工程师需要为项目编写脚本工具(前端工程师编写脚本通常会使用 JavaScript ,而不是 Python 或者 shell );
 
很多企业在使用 Electron 来开发桌面应用程序
 

JavaScript代码执行

如果我们编写一个 js 文件,里面存放 JavaScript 代码,如何来执行它呢?
  目前我们知道有两种方式可以执行:
 
将代码交给浏览器执行;
 
将代码载入到 node 环境中执行;
  如果我们希望把代码交给浏览器执行:
 
需要通过让浏览器加载、解析 html 代码,所以我们需要创建一个 html 文件
 
html 中通过 script 标签,引入 js 文件;
 
当浏览器遇到 script 标签时,就会根据 src 加载、执行 JavaScript 代码;
  如果我们希望把 js 文件交给 node 执行:
 
首先电脑上需要安装 Node.js 环境,安装过程中会自动配置环境变量;
 
可以通过终端命令 node js 文件的方式来载入和执行对应的 js 文件;
 
  
 

NodeREPL

什么是 REPL 呢?感觉挺高大上
 
REPL Read-Eval-Print Loop 的简称,翻译为 读 取 - 求值 - 输出 循环;
 
REPL 是一个简单的、交互式的编程环境;
  事实上,我们浏览器的 console 就可以看成一个 REPL
  Node 也给我们提供了一个 REPL 环境,我们可以在其中演练简单的代码。
 
 

Node程序传递参数

正常情况下 执行一个 node 程序,直接跟上我们对应的文件即可:
node index.js
 
但是,在某些情况下执行 node 程序的过程中,我们可能希望给 node 传递一些参数:
node index.js env=development 张三
 
如果我们这样来使用程序,就意味着我们需要在程序中获取到传递的参数:
 
获取参数其实是在 process 的内置对象中的;
 
如果我们直接打印这个内置对象,它里面包含特别的信息:
 
其他的一些信息,比如版本、操作系统等大家可以自行查看,后面用到一些其他的我们还会提到;
 
现在,我们先找到其中的 argv 属性:
  我们发现它是一 个数组,里面包含了我们需要的参数;

为什么叫argv呢?

你可能有个疑问,为什么叫 argv 呢?
 
C /C + + 程序中的 main 函数中,实际上可以获取到两个参数:
 
argc argument counter 的缩写,传递参数的个数;
 
argv argument vector 的缩写,传入的具体参数。
vector 翻译过来是矢量的意思,在程序中表示的是一种数据结构。
C + + Java 中都有这种数据结构,是一种数组结构;
JavaScript 中也是一个数组,里面存储一些参数信息;
 
我们可以在代码中,将这些参数信息遍历出来,使用:
 
 

Node的输出

console.log
  最常用的输入内容的方式: console.log
console.clear
  清空控制台: console.clear
  console.trace
  打印函数的调用栈: console.trace
  还有一些其他的方法,其他的一些 console 方法,可以自己在下面学习研究一下。
  https://nodejs.org/dist/latest-v14.x/docs/api/console.html
 

常见的全局对象

Node 中给我们提供了一些全局对象,方便我们进行一些操作:
 
这些全局对象,我们并不需要从一开始全部一个个学习;
 
某些全局对象并不常用,具体用到再讲
 
比如 module exports require() 会在模块化中讲到;

特殊的全局对象

为什么我称之为特殊的全局对象呢?
 
这些全局对象可以在模块中任意使用,但是在命令行交互中是不可以使用的;
 
包括: dirname
filename exports module require()
 
dirname :获取当前文件所在的路径:
  注意:不包括后面的文件名
filename :获取当前文件所在的路径和文件名称:
  注意:包括后面的文件名称

globalwindow的区别

在浏览器中,全局变量都是在 window 上的,比如有 document setInterval setTimeout alert console 等等
  Node 中,我们也有一个 global 属性
但是在浏览器中执行的 JavaScript 代码,如果我们在顶级范围内通过 var 定义的一个属性,默认会被添加到 window
对象上:
但是在 node 中,我们通过 var 定义一个变量,它只是在当前模块中有一个变量,不会放到全局中:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值