Nodejs 基础学习笔记

Node.js简介

  Node.js 是一个能够在服务器端运行 JavaScript 的开放源代码、跨平台 JavaScript 运行环境。Node.js 由 Node.js 基金会持有和维护,并与 Linux 基金会有合作关系。Node.js 采用 Google 开发的 V8 运行代码,使用事件驱动、非阻塞和异步输入输出模型等技术来提高性能,可优化应用程序的传输量和规模。这些技术通常用于数据密集的即时应用程序。

  Node.js 大部分基本模块都用 JavaScript 语言编写。在 Node.js 出现之前,JavaScript 通常作为客户端程序设计语言使用,以 JavaScript 写出的程序常在用户的浏览器上运行。Node.js 的出现使 JavaScript 也能用于服务端编程。Node.js 含有一系列内置模块,使得程序可以脱离 Apache HTTP Server 或 IIS,作为独立服务器运行。

Node.js 特点

  1. 它是一个 JavaScript 运行环境。
  2. 依赖于 Chrome V8 引擎进行代码解释。
  3. 事件驱动:在 Node 中,客户端请求建立连接,提交数据等行为,会触发相应的事件。在 Node 中,在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件,然后返回继续执行原事件的回调函数。
  4. 非阻塞 I/O:Node.js 中采用了非阻塞型 I/O 机制,在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率。
  5. 轻量可伸缩,适用于实时数据交互应用。
  6. 单线程:好处是减少内存开销,不用像多线程编程那样处处在意状态同步的问题。缺点是错误会引起整个应用退出。

Node.js 适用场景

  我们从 Node.js的特点中可以知道,Node.js擅长I/O处理,不善于计算(单线程的缺点)。因此Node.js适用于,当应用程序需要处理大量并发的I/O时。而在向客户端发出响应之前,应用程序内部并不需要进行非常复杂的处理的时候,Node.js也非常适合与websocket配合,开发长连接的实时交互应用程序。比如:聊天室,博客系统,考试系统等。

更新npm模块和Nodejs

更新npm模块

npm update -g

更新nodejs自身

npm install -g node

Nodejs全局对象

  JavaScript 中的全局对象是 window,而在 Node.js 中全局对象是 global,所有全局变量(除了global本身以外)都是global对象的属性,我们可以直接访问到 global 的属性。

下面介绍一些常用的全局变量和全局函数:

  1. __ filename全局变量表示当前正在执行的脚本的文件名。它将输出文件的绝对路径。比如创建一个filename-test.js文件,向其中写入:console.log(__filename);,使用node执行它即可得到该文件的绝对路径。

在这里插入图片描述

  1. __ dirname全局变量,表示当前执行脚本所在的目录。比如创建一个dirname-test.js文件,向其中写入代码console.log(__dirname),使用node执行它即可得到该文件所在的目录。

在这里插入图片描述

  1. setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb),只执行一次函数。比如创建一个 st.js 的文件,输入以下代码:
function foo() {
    console.log("Hello, syl!");
}

setTimeout(foo, 3000);  // 3秒后执行foo()函数

851e3b79b1ac44f18ca4a9ba16526de0.png

  1. clearTimeout(t) 全局函数用于停止一个之前通过 setTimeout() 创建的定时器。 参数 t 是通过 setTimeout() 函数创建的定时器。比如清除上面案例的定时器:

在这里插入图片描述

  1. setInterval(cb, ms) 与 setTimeout(cb, ms) 类似,不同的是这个方法会不停的执行函数。直到 clearInterval() 被调用或窗口被关闭,也可以按 Ctrl+C 停止。

使用Nodejs创建第一个应用

新建一个server.js文件,引入require模块,创建第一个node应用:

var http = require('http');

http.createServer(function(request, response) {
    response.writeHead(200, {'Content-Type': 'text/plain'});    // 发送HTTP头部
    response.end('Hello World\n');  // 发送响应消息
}).listen(8080);    // 监听8080端口

console.log('Server running at http://127.0.0.1:8080')

Nodejs包

  包用于管理多个模块及其依赖关系,可以对多个模块进行封装,包的根目录必须包含 package.json 文件。package.json 文件是 CommonJS 规范用于描述包的文件,符合 CommonJS 规范的 package.json 文件一般包含以下字段:

  1. name:包名。包名是唯一的,只能包含小写字母、数字和下划线。
  2. version:包版本号。
  3. description:包说明。
  4. keywords:关键字数组,用于搜索。
  5. homepage:项目主页。
  6. bugs:提交 bug 的地址。
  7. license:项目许可证。
  8. maintainers:项目维护者名单,是一个数组。
  9. contributors:项目贡献者名单,是一个数组。
  10. repositories:项目仓库托管地址,是一个数组。
  11. dependencies:项目的包依赖。
{
    "name": "First",
    "description": "First package.",
    "version": "0.1.0",
    "keywords": [
        "study",
        "nodejs"
     ],
    "licenses": [{
        "type": "Apache License v2",
        "url": "http://www.apache.org/licenses/apache2.html"
    }],
    "dependencies": { 
        "webkit": "1.2",
        "ssl": { 
            "gnutls": ["1.0", "2.0"],
            "openssl": "0.9.8"
        }
    }
}

如果想了解更多的npm命令,可以前往这里(https://www.npmjs.cn):

在这里插入图片描述

Nodejs模块

  在 JavaScript 中,我们通常把 JavaScript 代码分成几个 js 文件,然后在浏览器中将这些 js 文件合并运行。但是在 Node.js 中,是以模块为单位来划分所有功能的,每一个模块对应一个 js 文件,每一个模块中定义的全局变量和函数的作用范围也被限定在这个模块之内,只有使用 exports 对象才能导出到外部使用。

  Node.js官方提供了很多模块,这些模块分别实现了一种功能,如操作文件及文件系统的模块 fs,构建http服务的模块http,处理文件路径的模块path等,当然我们也可以自己编写模块。

使用模块

首先创建一个模块MyModule.js,

function foo() {
    console.log("Hello syl");
}

module.exports.foo = foo;   // 导出foo()函数

再新建一个index.js文件用于引入模块:

var hello = require('./MyModule.js');   // 使用require()引入模块

hello.foo();    // 调用模块hello内的函数foo()

核心模块

  使用 require 加载模块,以’/’ 为前缀的模块是文件的绝对路径,‘./’ 为前缀的模块是相对于当前文件而言的。当没有以 ‘/’、‘./’ 或 ‘…/’ 开头来表示文件时,这个模块必须是一个核心模块或加载自 node_modules 目录。如果给定的路径不存在, require() 会抛出一个 code 属性为 ‘MODULE_NOT_FOUND’ 的 Error。

  核心模块定义在 Node.js 源代码的 lib/ 目录下。require() 总是会优先加载核心模块。 例如,require('http') 始终返回内置的 HTTP 模块,即使有同名文件。

Nodejs中的函数

  在 JavaScript 中,一个函数可以作为另一个函数的参数,毕竟函数名本身只是一个指针。Node.js 中函数的使用与 Javascript 类似。

在这里插入图片描述
在这里插入图片描述

Nodejs异步编程

  Node.js 异步编程的直接体现就是回调。回调函数在完成任务后就会被调用,Node.js 中使用了大量的回调函数,Node.js 的所有 API 都支持回调函数。回调函数一般作为函数的最后一个参数出现。

阻塞代码实例

准备好test.txt文件后,使用如下代码读入文件:

var fs = require("fs");
var data = fs.readFileSync('test.txt');     // 同步读取文件,只有文件读取完后才能执行下一步操作

console.log(data.toString());
console.log("程序执行完毕!");

在这里插入图片描述

非阻塞代码

非阻塞代码主要采用了异步回调的方式。

将上述fs.js中的代码改为:

var fs = require("fs");
fs.readFile('test.txt', function(err, data) {
    if(err)
        return console.error(err);  // 打印错误消息
    console.log(data.toString());
})

console.log("程序执行完毕!");

在这里插入图片描述

  注意,此时控制台打印的消息与之前使用阻塞读取的方式打印出的内容是相反的(因为异步读取不需要等待文件全部读取完,就可以直接进行下一步操作)。

Nodejs事件

  大多数 Node.js 核心 API 构建于惯用的异步事件驱动架构,其中某些类型的对象(又称触发器,Emitter)会触发命名事件来调用函数(又称监听器,Listener)。

  比如,fs.readStream 打开文件时会发出一个事件。可以通过 require("events");获得 event 模块。通常,事件名采用“驼峰法”命名。

EventEmitter类

  所有能触发事件的对象都是 EventEmitter 类的实例。这些对象有一个 eventEmitter.on() 函数,用于将一个或多个函数绑定到命名事件上。当 EventEmitter 对象触发一个事件时,所有绑定在该事件上的函数都会被同步地调用。

添加监听器

使用emitter.on()为事件绑定一个监听器:

emitter.on(eventName, listener)

在这里插入图片描述

另外,我们通常看到的emitter.addListener(eventName, listener)emitter.on(eventName, listener) 的别名。

  默认情况下,事件监听器会按照添加的顺序依次被调用。emitter.prependListener() 方法可将事件监听器添加到监听器数组的开头。
在这里插入图片描述

调用监听器

使用emitter.emit(eventName[, ...args])调用事件的监听器,调用的顺序正是监听器被绑定到事件上时的顺序。

在这里插入图片描述

只执行一次的监听器

  使用前面介绍的eventEmitter.on(eventName, listener) 注册监听器时,监听器会在每次触发命名事件时被调用。如果事件被触发多次,那么监听器就也会被执行多次。

在这里插入图片描述

  如果要注册一个只执行一次的监听器,则可以使用 eventEmitter.once(eventName, listener) 函数,它会注册最多可调用一次的监听器。当事件被触发时,监听器会先被注销,然后才开始调用。

在这里插入图片描述

移除监听器

使用 emitter.removeListener(eventName, listener) 移除监听器。

在这里插入图片描述

  removeListener() 最多只会从监听器数组中移除一个我们指定的监听器,可以通过多次调用 removeListener() 的方式来一个个的移除我们需要移除掉的监听器。

error事件

  当 EventEmitter 实例出错时,会触发 ‘error’ 事件。如果没有为 ‘error’ 事件注册监听器,则当 ‘error’ 事件触发时,会抛出错误、打印堆栈跟踪、并退出 Node.js 进程。

在这里插入图片描述

所以说,通常情况下,我们要为会触发 error 事件的对象设置监听器,避免遇到错误后导致整个程序崩溃。

在这里插入图片描述

Nodejs中http和fs模块

Http模块

createServer([requestListener]);

  requestListener是一个绑定到request事件上的监听器,每次当服务器收到请求时,就会触发request事件,进而执行该监听器函数。

  requestListener()函数包括两个参数——request和response,调用request对象的属性和方法就可以拿到所有 HTTP 请求的信息,操作 response 对象的方法,就可以把 HTTP 响应返回给浏览器。

使用response对象向客户端返回内容:

在这里插入图片描述

使用request对象的几个属性:
在这里插入图片描述

Fs模块

  在 Node.js 中绝大部分需要在服务器运行期反复执行业务逻辑的代码,必须使用异步加载,否则,同步代码在执行时期,服务器将停止响应,因为 Node.js 是单线程。

  服务器启动时如果需要读取配置文件,或者结束时需要写入到状态文件时,可以使用同步代码,因为这些代码只在启动和结束时执行一次,不影响服务器正常运行时的异步执行。

打开和关闭文件

使用open()异步打开文件:
在这里插入图片描述

上述代码回调函数中的fd是一个文件流操作对象,可以使用它来关闭文件,如fs.close(fd, callback);

使用fs.openSync()同步打开文件。

写入和读取文件内容

使用read()读取文件内容:

fs.read(fd, buffer, offset, length, position, callback);

fd: 使用fs.open() 打开文件时返回的文件描述符。
buffer:数据一次性写入的缓冲区。
offset:缓冲区中开始写入的偏移量,一般我们设为0length:是一个整数,指定我们要一次读取的字节数。
position:指定从文件中开始读取的位置。 如果 position 为 null,则从当前文件位置读取数据,并更新文件读取指针位置。
callback:回调函数,有三个参数 err, bytesRead, buffer。err 为错误信息, bytesRead 表示读取的字节数,buffer 为缓冲区对象。

在这里插入图片描述

使用write()向文件写入内容:

fs.write(fd, buffer, offset, length, position, callback);

  可见,write()所需的参数和open()一样,唯一不同的是open()中的buf指的是存储从文件中读取到的数据的缓冲区,而write()中的buf存储的是即将写入到文件的内容。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值