nodejs——介绍

简介
node.js是一个运行在chromeJavascript运行环境下(俗称GoogleV8引擎)的开发平台,用来方便快捷的创建服务器端网络应用程序。你可以把它理解为一个轻量级的JSP或PHP环境,但是用来开发Web应用的话,有时要便捷很多。

nodejs 特点
Node.js 作为一门新兴的后台语言平台,旨在帮助程序员快速构建可伸缩的应用程序,自发布以来,广受开发人员的关注。Node.js 之所以这么受欢迎归功于它的一些吸引人的特点。

  • 它是一个 JavaScript 的运行环境:Node.js 作为运行环境可以让 JavaScript 脱离浏览器,在服务器端单独执行。如果客户端和服务器端使用相同的开发语言,可以在很大程度上达到客户端和服务器端代码的共用。
  • 依赖于 Chrome V8 引擎进行代码的解析:Chrome V8 负责在非浏览器解析情况下解析 JavaScript 代码。
  • 事件驱动(Event-Driven):对于事件驱动来说,在学习 JavaScript 的初级阶段,都会接触到事件,如clickload等,这些事件通常都会绑定在某个页面元素上,然后为其指定事件处理函数,当事件被触发时才会执行相应的处理函数。可以说这样的事件处理机制就是标准的事件驱动机制。
  • 非阻塞I/O(non-blocking I/O):提到非阻塞 I/O,首先就有必要了解一下阻塞 I/O,I/O(input/output)表述的是输入/输出操作,阻塞 I/O 可以理解为被阻塞了的输入/输出操作,在服务器端有很多会涉及阻塞 I/O 的操作,例如在读取文件的过程中,需要等待文件读取完毕后才能继续执行后面的操作, Node.js 中使用事件回调的方式来解决这种阻塞 I/O 的情况,避免了阻塞 I/O 所需的等待,所以说它具有非阻塞 I/O 的特点。
  • 轻量、可伸缩,适用于实时数据交互应用:在 Node.js 中,Socket 可以实现双向通信,例如聊天室就是实时的数据交互应用。
  • 单进程、单线程:进程就是一个应用程序的一次执行过程,它是一个动态的概念。而线程是进程中的一部分,进程包含多个线程在运行。单线程就是指进程中只有一个线程,阻塞 I/O 模式下一个线程只能处理一个任务,而在非阻塞 I/O 模式下,一个线程永远在处理任务,这样 CPU 的利用率是 100%。Node.js 采用单线程,利用事件驱动的异步编程模式,实现了非阻塞的 I/O。

优点及缺点
优点:Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,异步编程,轻量、可伸缩,适于实时数据交互应用。
缺点:单进程,单线程,只支持单核cpu,不能充分的利用多核cpu服务器。一旦这个进程崩掉,那么整个web服务就崩掉了。

nodejs环境搭建
要想搭建环境就要先了解什么是npm
npm其实是Node.js的包管理工具(package manager)
为啥我们需要一个包管理工具呢?
因为我们在Node.js上开发时,会用到很多别人写的JavaScript代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。
于是一个集中管理的工具应运而生:大家都把自己开发的模块打包后放到npm官网上,如果要使用,直接通过npm安装就可以直接用,不用管代码存在哪,应该从哪下载。
更重要的是,如果我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块X和模块Y,npm可以根据依赖关系,把所有依赖的包都下载下来并管理起来。否则,靠我们自己手动管理,肯定既麻烦又容易出错。

学习 npm 其实就是学习里面相关的命令:
查看 npm 版本指令:

npm -v
npm version

在这里插入图片描述

初始项目

npm init
npm init -y

安装模块和卸载模块

// 安装模块
npm install <模块名>
npm i <模块名>

// 卸载模块
npm uninstall <模块名>
npm un <模块名>

安装模块需要联网,也需要时间一般几秒到十几秒即可,这个图就是正在下载模块。
在这里插入图片描述

在这里插入图片描述

全局安装局部安装的区别?
全局安装是安装到nodejs的安装目录,一般例如脚手架工具、nodemon、typescript 这些,一般都是全局安装,而且那边的bin目录是在你的path中的,你可以很方便在命令行中直接调用那里的工具。
本地安装安装到本地往上找package.json存在的目录的node_modules中。用来构建本地项目(或者支撑nodejs运行,用require可以直接引用)。

查看包目录

npm root -g

镜像安装
由于 npm 的服务器是在国外,就导致经常我们安装包的时候,容易失败。
有两个解决方案(1)安装 cnpm (2)修改npm的镜像
cnpm 是国内淘宝团队推出的一个工具,cnpm 工具拉包的时候,是从国内的服务器来进行包拉取,cnpm 和 npm同步的频率是5分钟就会同步一次。

npm i -g cnpm

在这里插入图片描述

在全局安装了 cnpm 之后,后面我们安装模块就可以使用

cnpm i <模块名>

接下来我们来看第二个解决方案。

npm config list  //该命令能够查看 npm 的配置。

通过该配置,我们可以看到 npm 默认的镜像指向 npmjs,那么,我们就可以将这个指向修改成 taobao

npm config set registry https://registry.npm.taobao.org

然后使用 npm config gset registry查看镜像指向
在这里插入图片描述
cnpm 是国内淘宝团队推出的一个工具,cnpm 工具拉包的时候,是从国内的服务器来进行包拉取,cnpm 和 npm同步的频率是5分钟就会同步一次,所以不用担心添加的模块找不到。

查看安装的模块
有些时候,我们想要知道当前安装了什么模块,使用 npm list 命令,可以使用 --depth 后缀来调节深度

npm list --depth <0|1|2>

深度由自己决定

清除缓存
有些时候,我们安装依赖失败,是因为之前的包有残留,所以这个时候需要清除缓存

npm cache clean --force

有趣的是,在清楚缓存的时候还会提醒你 o^o
在这里插入图片描述
yarn
yarn 同样是一个包管理器,是 Facebook,Google,Exponent 和 Tilde 开发的一款新的 JavaScript 包管理工具。
相比 npm,解决了一些npm存在的问题:

  • 安装的时候无法保证速度/一致性
  • 安全问题,因为 npm 安装时允许运行代码

安装方式如下:

npm i -g yarn

yarn 也同样存在修改镜像的问题,基本和 npm 大同小异:
修改如下:

yarn config set registry https://registry.npm.taobao.org

获取镜像如下:

yarn config get registry

nodejs 最大的两个特点
一个是异步无阻塞,另一个是事件驱动

传统的同步代码,当线程在执行中遇到磁盘读写、网络通信等 I/O 操作时,通常要耗费较长的时间。这时操作系统会剥夺这个线程的 CPU 控制权,使其暂停执行,同时将资源让给其他的工作线程,这种线程调度方式称为阻塞。

当 I/O 操作完毕时,操作系统会将这个线程的阻塞状态解除,恢复其对 CPU 的控制权,令其继续执行。这种 I/O 模式就是通常的同步式 I/O(Synchronous I/O)或阻塞式 I/O(Blocking I/O)。如下图:在这里插入图片描述
我们先来看一看阻塞,下面的代码是一个阻塞I/O的示例:

const fs = require('fs');
console.log('开始写入文件');
try{
    // try 里面是尝试执行一段代码,如果出现问题,catch 负责捕捉
    console.log('正在写入文件');
    fs.writeFileSync('./test.txt','这是一个测试');
} catch(e) {
    console.log('文件写入失败');
    console.log(e.message);
}
console.log('文件写入完毕');

在这里插入图片描述
可以看到try catch阻塞了最后一行代码的执行
nodejs 采用的是异步编程。使用异步式 I/O 与事件紧密结合的编程模式,可以很好的解决 I/O 阻塞的问题。

当线程遇到 I/O 操作时,不会以阻塞的方式等待 I/O 操作的完成或数据的返回,而只是将 I/O 请求发送给操作系统,继续执行下一条语句。当操作系统完成 I/O 操作时,以事件的形式通知执行 I/O 操作的线程,线程会在特定时候处理这个事件。

为了处理异步 I/O,线程必须有事件循环,不断地检查有没有未处理的事件,依次予以处理。如下图:
在这里插入图片描述
下面的代码演示了非阻塞I/O的形式:

const fs = require('fs');
console.log('开始写入文件');
fs.writeFile('./test2.txt','这是一个测试2',function(err){
    if(err) throw err;
    console.log('正在写入文件');
})
console.log('文件写入完毕');

在这里插入图片描述
可以看到最后一行代码没有被阻塞。
注意:在 nodejs 中,异步回调的特点,错误优先。
如果是同步代码,可以通过 try…catch 的方式来捕捉错误,但是在异步的情况下,我们无法使用 try…catch 的方式来捕捉错误,所以在 nodejs中规定,把错误对象作为回调函数的第一个参数。

if(err) throw err;

事件驱动
nodejs 的另外一个特点,事件驱动,这里有两个知识点:EventEmitter 和 事件驱动模式。

EventEmitter
在浏览器环境下,常见的事件有 click、mouseup、mousedown 等,这些事件是浏览器环境为我们提前定义好了的。在 nodejs 里面,我们就可以自己去定义事件类型,自己去触发这个事件。
下面是一个 eventEmitter 的示例:

const EventEmitter = require('events').EventEmitter;
const event = new EventEmitter();
// 手动定义一个 test 事件
event.on('test',function(){
    console.log('test 事件被触发');
});
// emit 方法表示我要触发一个事件,事件的名字叫做 test
setTimeout(function(){
    event.emit('test')
},2000)

还可以绑定多个事件:

const EventEmitter = require('events').EventEmitter;
const event = new EventEmitter();
// 手动定义一个 test 事件
event.on('test',function(){
    console.log('test 事件被触发');
});
event.on('test2',function(){
    console.log('test2 事件被触发');
});
// emit 方法表示我要触发一个事件,事件的名字叫做 test
setTimeout(function(){
    event.emit('test');  //事件一
    event.emit('test2');  //事件二
},2000)

在实际的开发中,我们一般不会用到 EventEmitter,但是这个 EventEmitter 是其他很多模块的父类,fs,net,http 等这些模块都是 EventEmitter 子类。

事件驱动模式
当代码在执行过程中遇到类似 AJAX 请求、setTimeout 时间延迟、DOM事件的用户交互等操作时,这些任务可能会消耗较长的时间去执行,但其实却并不消耗 CPU。

可由于 JavaScript 单线程的特点,导致后面的代码也必须等待。而这种无意义的等待成了一种空等、资源浪费。因此 JavaScript 语言的设计者最终在 JavaScript 的执行机制中引出了异步执行操作。

于是,程序中所有的任务分成了两种,一种是同步任务,另一种是异步任务。

同步任务(synchronous):在主线程上排队执行的任务,只有前一个同步任务执行完毕,才能执行后一个同步任务;

异步任务(asynchronous):不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程同步任务执行完毕,"任务队列"开始通知主线程,请求执行异步任务,该任务才会进入主线程执行。

JavaScript 代码的执行过程中,除了依靠函数调用栈来搞定函数的执行顺序外,还依靠任务队列(task queue)来搞定另外一些代码的执行。

JavaScript 中,任务队列分为两类:

  • 宏任务队列(macro tasks):包括 script(整体代码)、setTimeout、setInterval、I/O、UI rendering 等。
  • 微任务队列(micro tasks):包括 Promise、MutationObserver(HTML5 新特性) 等。

来自不同任务源的任务会进入不同的任务队列,宏任务队列可以有多个,微任务队列只有一个。
在这里插入图片描述
事件循环的顺序,决定了 JavaScript 代码的执行顺序。

  • 取出一个宏任务执行。执行完成后,进入下一步。
  • 取出一个微任务执行。执行完成后,继续取出下一个微任务执行。直到微任务队列为空,进入下一步。
  • 更新 UI 渲染。
  • 也就是说,事件循环的第一次循环从宏任务 script(整体代码)开始。之后全局上下文进入函数调用栈。直到调用栈清空(只剩全局),然后执行所有的微任务。当所有可执行的微任务执行完毕之后。循环再次从宏任务开始,当其中一个宏任务队列执行完毕,然后再执行所有的微任务,这样一直循环下去。

其中,第3步(更新 UI 渲染)会根据浏览器的逻辑,决定要不要马上执行更新。毕竟更新 UI 成本大,所以,一般都会比较长的时间间隔,执行一次更新。

nodejs 系统架构

在这里插入图片描述

我们整个 nodejs,是由 V8 + 由C/C++ 的一些库一起封装而成的。不是说整个 nodejs 是单线程,只能说nodejs 中负责处理 js 代码的那个部分是单线程,nodejs 中处理异步模块采用的 C/C++ 那些库,使用的是多线程的方式来执行的代码。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值