• 一文简单入门Node.js


    前言

    JavaScript语言是网站开发必不可少的语言,只要有浏览器就能运行起来JavaScript代码。另外JavaScript还能单独运行在Node.js环境中,本文章重点介绍Node.js相关的基础内容,为深入了解Node.js铺路,后续会更新Node.js深入介绍。

    Node.js安装及使用

    Windows安装很简单,在官网下载安装就行了,地址是 https://nodejs.org/zh-cn 。安装完后在控制台输入node -v 后能有显示则证明安装成功,这个时候可以开始各种倒腾了。

    Centos安装如下:

    cd /root
    wget https://nodejs.org/dist/v14.20.0/node-v14.20.0-linux-x64.tar.xz
    tar xvf node-v14.20.0-linux-x64.tar.xz
    ln -s /root/node-v14.20.0-linux-x64/bin/node /usr/local/bin/node
    ln -s /root/node-v14.20.0-linux-x64/bin/npm /usr/local/bin/npm 
    npm config set registry https://registry.npm.taobao.org
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    root@localhost:~$ node -v         
    v14.20.0
    
    • 1
    • 2

    可以创建一个JavaScript文件,用node命令来执行。

    root@localhost:~$ echo 'console.log("hello world!")'> helloworld.js     
    root@localhost:~$ node  helloworld.js
    hello world!
    
    • 1
    • 2
    • 3

    Node.js源码初步分析

    Node.js是怎么实现JavaScript代码执行的呢?Node.js源码地址是 https://github.com/nodejs/node/tree/main ,查看源码我们可以看到deps文件夹下面有很多依赖组件,其中最为核心的依赖组件是v8和uv文件夹。

    ├── deps
    │   ├── acorn
    │   ├── base64
    │   ├── brotli
    │   ├── cares
    │   ├── cjs-module-lexer
    │   ├── corepack
    │   ├── googletest
    │   ├── histogram
    │   ├── icu-small
    │   ├── llhttp
    │   ├── nghttp2
    │   ├── ngtcp2
    │   ├── npm
    │   ├── openssl
    │   ├── undici
    │   ├── uv
    │   ├── uvwasi
    │   ├── v8
    │   └── zlib
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    组件名功能描述
    v8V8 是 Google 发布的开源 JavaScript 引擎,采用 C++ 编写,在 Google 的 Chrome 浏览器中被使用。用于编译和执行JavaScript源代码,处理对象的内存分配,以及进行垃圾回收。
    uvuv即为libuv,libuv 是一个多平台支持库,专注于异步 I/O,集成该组件能够更简单的实现异步I/O的服务端开发,同时该组件还为Node.js提供线程池,文件系统等功能。它本来就是为Node.js开发的,但它也被Luvit,Julia,uvloop和其他集成使用。
    nghttp2nghttp2 是一个用 C 实现的 HTTP/2 库,支持 h2c,为其提供 HTTP/2 相关功能。
    caresc-ares 是一个异步DNS解析器库。它为Node.js提供异步DNS并行查询功能。

    Node.js基于v8 JavaScript 引擎和libuv实现了单线程/异步IO的JavaScript运行环境,显然没有线程资源抢夺场景,但是Node.js核心亮点不在于提供单线程JavaScript运行环境,而在于实现了跨平台的异步IO,其中linux系统下通过IO多路复用(epoll)+线程池来实现,Mac OS X系统下则是通过IO多路复用(kqueue)+线程池来实现,由于IO多路复用的实现依赖系统底层的实现,所以实现方法不一样。严格来说在linux和Mac OS X使用的都是同步IO,因为IO多路复用(select,poll,epoll等)就是同步IO,只是引入了线程池模拟实现了异步IO,让大家能够轻松使用异步语法(回调函数的处理),以下是官网提供的libuv实现异步IO的技术架构图。
    在这里插入图片描述

    由于JavaScript程序是单线程执行,代码肯定要有一定的执行顺序逻辑,定时器以及异步的回调函数何时执行也有讲究,Node.js提供了event_loop功能(事件循环机制)来判断什么时候执行。
    比如下面的代码,输出的顺序是1,4,2,3。

    console.log('1');
    setTimeout(() => {
        console.log('2');
    }, 1);
    setTimeout(() => {
        console.log('3');
    }, 1);
    console.log('4');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    比如下面的代码,在5秒后输出1。

    setTimeout(() => {
      console.log(1);
    }, 1);
    /*模拟费时间的cpu计算,也可以用其他真实耗时的算法,比如计算素数和DFS全排列等*/
    let now = new Date();
    while(new Date () - now < 5*1000){}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    从以上2个case可以总结出以下执行规则。
    1.同步代码执行优先级都比setTimeout高。
    2.setTimeout的定时不精准,会被其他同步代码影响。单线程定时器出现这个问题不出意外。
    要了解更多的执行顺序的规则,就必须了解Node.js的事件循环机制。

    Node.js事件循环机制

    根据上面的case,可以大概得出Node.js的执行代码逻辑。
    1.主线程执行同步代码。
    2.主线程将异步任务插入到待执行任务队列中。
    3.经过事件循环逻辑处理,按优先级执行队列里面的任务。
    上面的逻辑应该比较容易理解,以下是官网提供的事件循环具体执行细节,包含了6个执行阶段。

       ┌───────────────────────────┐
    ┌─>│           timers          │
    │  └─────────────┬─────────────┘
    │  ┌─────────────┴─────────────┐
    │  │     pending callbacks     │
    │  └─────────────┬─────────────┘
    │  ┌─────────────┴─────────────┐
    │  │       idle, prepare       │
    │  └─────────────┬─────────────┘      ┌───────────────┐
    │  ┌─────────────┴─────────────┐      │   incoming:   │
    │  │           poll            │<─────┤  connections, │
    │  └─────────────┬─────────────┘      │   data, etc.  │
    │  ┌─────────────┴─────────────┐      └───────────────┘
    │  │           check           │
    │  └─────────────┬─────────────┘
    │  ┌─────────────┴─────────────┐
    └──┤      close callbacks      │
       └───────────────────────────┘
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    阶段概述
    定时器:本阶段执行已经被 setTimeout() 和 setInterval() 的调度回调函数。
    待定回调:执行延迟到下一个循环迭代的 I/O 回调。
    idle, prepare:仅系统内部使用。
    轮询:检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 setImmediate() 调度的之外),其余情况 node 将在适当的时候在此阻塞。
    检测:setImmediate() 回调函数在这里执行。
    关闭的回调函数:一些关闭的回调函数,如:socket.on(‘close’, …)。
    这些概述来自官网:https://nodejs.org/zh-cn/docs/guides/event-loop-timers-and-nexttick/

    Node.js工程实践

    Node.js版本管理

    平时开发过程可能涉及不同的Node.js版本切换,可以通过安装nvm来进行管理,下载地址是https://github.com/nvm-sh/nvm ,下面是一些相关的命令例子。

    root@localhost:~$ nvm use 16
    Now using node v16.15.1 (npm v8.11.0)
    root@localhost:~$ node -v
    v16.15.1
    root@localhost:~$ nvm install 12
    Downloading and installing node v12.22.12...
    Downloading https://nodejs.org/dist/v12.22.12/node-v12.22.12-darwin-x64.tar.gz...
    ########################################################################################################################### 100.0%
    Computing checksum with shasum -a 256
    Checksums matched!
    Now using node v12.22.12 (npm v6.14.16)
    root@localhost:~$ node -v
    v12.22.12
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    Node.js 工程依赖包管理

    Python工程可以通过pip工具来管理依赖包,JAVA工程可以通过maven工具来管理依赖包,自然Node.js也得有个依赖包管理工具。Node.js则是用npm来管理工程依赖包。
    创建一个文件夹,然后cd进去执行npm init就是初始化Node.js工程,同时会在本地生成package.json文件。

    mkdir app && cd app &&  npm init
    
    • 1

    package.json文件内容如下

    {
      "name": "app",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "license": "ISC"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    可以通过npm install来安装其他的依赖包,如下安装koa(基于Node.js的web开发框架)。

    npm install koa --save-dev
    
    • 1

    package.json文件更新如下

    {
      "name": "app",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "koa": "^2.13.4"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Node.js应用场景

    跨平台开发(PC端,移动端)
    嵌入式相关开发(Node.js轻量而且JavaScript编程简单,如手表系统/路由器系统等)
    全栈开发(统一前后端语言)

    No de => De no?

    和Node一样提供JavaScript运行环境的还有一个叫Deno的程序,从名字上来看就是Node按No de的倒序,但是2者之间的开源项目关联不大,具体可以查看官网安装和使用(https://deno.land/),这里不展开介绍,额外引出的一个探索话题。

    未完,持续更新。

  • 相关阅读:
    ESP 特权隔离机制—案例研究
    Web应用开发 - 实训三 B Servlet基础
    【无标题】
    vue中动态引入图片为什么要是require, 你不知道的那些事
    彻底了解线程池的原理——40行从零开始自己写线程池
    【寒枫顾辞老航小说传】第一回:梦回大唐
    Java队列相关面试题
    使用生成式 AI 增强亚马逊云科技智能文档处理
    uniapp获取视频第一帧作为封面图
    Python基于OpenCV的异常行为检测系统[源码&部署教程]
  • 原文地址:https://blog.csdn.net/bojie5744/article/details/126605903