JS高级--node.JS

大家需要知道nodejs 的出现,允许我们js开发人员使用 js 来开发服务器。

node.js 特点
  • 它是一个 javascript 的运行环境

  • 依赖于 V8 引擎进行代码解析

  • 事件驱动

  • 非阻塞 I/O

  • 轻量、可伸缩

  • 单线程:指的是 nodejs 在运行 js 代码的时候是单线程,并不是说整个 node.js 是单线程。

REPL 环境,英语全称 read-eval-print-loop,翻译成中文就称之为“即时运行环境”,在这个环境里面,可以运行 js 代码。

该环境的意义在于测试一些小段的代码。一般比较的成熟的语言都提供REPL环境。

模块化

如果想要开发大型应用,必须要有模块化。

最早,js 是没有模块话的概念的,因为最早 js 的定位就是脚本语言(玩具语言)。

但是随着 js 走向服务器端的开发,那么必然也是需要模块化。

总结一下模块化的好处:

  • 生产效率高

  • 维护成本低

接下来我们就需要看一下 node.js 中如何实现模块化,一般来讲,分为3类

  • 文件模块

  • 核心模块

  • 第三方模块

引入模块统一使用 require 方法。

const readline = require('readline-sync');  
文件模块
require(“路径.扩展名”)

// 相对路径
require('./index.js');
require('../index.js');
// 绝对路径
require('/src/index.js'); // 一个斜杠 / 代表根目录  
核心模块

核心模块是指 nodejs 内置的模块,比如 fs、os、http、path...

require('fs');
require('path');
第三方模块

所谓第三方模块,就是指非官方开发,而是第三方开发的。

require('readline-sync'); 
CommonJS 规范

之前,我们接触过一个东西,叫做 ECMAScript,它就是 js 语言的规范。

我们可以这么说,ECMAScript 是规范,JavaScript 是这个规范的一种实现,例如 adobe 的 flash 里面使用的 ActionScript 也是一种 ECMAScript 的实现。

ECMAScript 虽然说是 js 的规范,但是它只管客户端,Commonjs 管的就是浏览器端以外的环境。

CommonJS一些著名的实现,node.js、mongodb、couchdb、coffiejs。

CommonJS 中的模块导入导出

在 CommonJS 中,通过 module.exports 来导出一个模块,通过 require 来导入一个模块。

module.exports 可以将他想象成一个对象。

// index.js
// 导出模块
module.exports.name = 'xiejie';
module.exports.sayHello = function(){
    console.log('Hello');
}

// index2.js
// 导入模块
let obj = require('./index.js');
console.log(obj.name); // xiejie
obj.sayHello(); // Hello

  为了让开发人员使用起来更加方便,nodejs 还提供了一个 exports 的对象,它是指向 module.exports 的。

// index.js
// 导出模块
exports.name = 'xiejie';
exports.sayHello = function(){
    console.log('Hello');
}

// index2.js
// 导入模块
let obj = require('./index.js');
console.log(obj.name); // xiejie
obj.sayHello(); // Hello

  但是两者之间是有区别,上面我们在介绍 exports 的时候,我们有讲过, exports 是指向 module.exports 的,也就是说,最终,导出的是 module.exports

// index.js
module.exports = 'F71';
// index2.js
let obj = require('./index.js');
console.log(obj); // F71


// index.js
exports = 'F71';
// index2.js
let obj = require('./index.js');
console.log(obj); // {}

  

nodejs 的两大特点

nodejs 有两个最大的特点:异步无阻塞事件驱动

1. 异步无阻塞

传统的同步代码,如果在它的线程中遇到磁盘读写、发送请求,就会阻塞后面的代码。像 Java 这种语言,采用的是多线程的方式来解决这个问题。

js 采用的异步无阻塞的方式来解决这个问题,遇到异步代码,会交给异步模块。

下面是同步处理阻塞IO的示例:

const fs = require('fs');
console.log('开始写入文件');
// 如果要捕获错误,使用 try...catch
try {
    // 书写尝试执行的代码
    const content = fs.readFileSync('./test111.txt');
    console.log(content.toString());
} catch (err) {
    console.log(err);
}
console.log('结束写入文件');

  异步的方式:

const fs = require('fs');
console.log('开始写入文件');
fs.readFile('./test.txt',function(err,data){
    if(err) throw err;
    console.log(data.toString());
})
console.log('结束写入文件');

  

通过上面的例子,我们可以看出,在 node中,由于采用异步的方式来处理阻塞代码,所以在回到函数中,采用错误优先原则。

  1. 事件驱动

这里其实就是两个知识点:EventEmitter,事件驱动模式,EventEmitter 是 node 里面为我们提供的一个模块,允许我们自定义事件。

 之前我们学过事件,例如 click,mouseenter,mousemove 这些。

例如:

const EventEmitter = require('events').EventEmitter;

const event = new EventEmitter();

// 手动定义一个事件
event.on('F71',function(){
    console.log('你触发了这个事件');
})

// 手动来触发
setTimeout(function(){
    event.emit('F71');
},2000);
nodejs 系统架构 

nodejs 的架构如下图:

 

 

 

该图展示了整个 Node 的运行原理,从左到右,从上到下,整个 Node 被分为了 4 层,分别是应用层V8 引擎层Node API层LIBUV层

应用层:即 JavaScript 交互层,常见的就是 Node 的模块,比如httpfs

V8 引擎层:即利用 V8 引擎来解析 JavaScript 语法,进而和下层 API 交互。

NodeAPI 层:为上层模块提供系统调用,一般是由 C 语言来实现,和操作系统进行交互。

LIBUV 层:是跨平台的底层封装,实现了事件循环、文件操作等,是 Node 实现异步的核心。

无论是 Linux 平台还是 Windows 平台,Node 内部都是通过线程池来完成异步 I/O 操作的,而 LIBUV 针对不同平台的差异性实现了统一调用。

当我们使用 Node.js 的时候,会在 JavaScript 中触发一些命令调用方法,这些方法会被包装成一个对象,放入线程池,然后前面的方法就返回了,继续执行下面的 JavaScript 代码。

线程池中采用多线程的方式执行,执行完的对象放入事件循环队列。

事件循环队列采用类似 while(true) 这种循环的方式,不断的查看是否有事件,并且读取是否包含回调,由于前面回调函数被包装到对象中,这里直接调用执行就可以了。

因此,Node.js 的单线程仅仅是指 JavaScript 运行在单线程中,而并非整个 Node.js 运行环境是单线程。

 

posted @ 2020-12-30 22:03  瓜豆のO泡  阅读(89)  评论(0)    收藏  举报