目录
querystring.parse(str[, sep[, eq[, options]]])
querystring.stringify(obj[, sep[, eq[, options]]])
学习⽂档
NodeJS学习⽂档地址:Node.js 简介环境搭建
NodeJS语⾔需要运⾏在Nodejs软件中,Nodejs软件的下载地址
下载之后直接进⾏安装即可。安装之后使⽤ node -v 来查看nodejs的版本号。安装了nodejs软件后,会⾃动携带了npm包管理⼯具。因为npm包管理⼯具默认是从国外下载项⽬所需的依赖,⽐较慢,所以nodejs安装之后可以修改npm的仓库地址:
$ npm config set registry https://registry.npm.taobao.org
也可以全局安装cnpm, cnpm直接使⽤的就是国内淘宝镜像,使⽤cnpm也可快速下载项⽬所需的依赖:
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
REPL环境
Node.js REPL(Read Eval Print Loop:交互式解释器)表示⼀个电脑的环境,类似 Windows 系统的终端或 Unix/Linux,shell,我们可以在终端中输⼊命令,并接收系统的响应。
使⽤ node 命令进⼊NodeJS软件的REPL环境, REPL环境中执⾏以下任务:
读取 - 读取⽤户输⼊,解析输⼊的 Javascript 数据结构并存储在内存中。
执⾏ - 执⾏输⼊的数据结构
打印 - 输出结果
循环 - 循环操作以上步骤直到⽤户两次按下 ctrl-c 按钮退出。使⽤两次 ctrl+C 来退出REPL环境
案例体验
Node.js 服务器应⽤
Node.js 应⽤是由哪⼏部分组成的:
1.引⼊ required 模块: 我们可以使⽤ require 指令来载⼊ Node.js 模块。
2.创建服务器: 服务器可以监听客户端的请求,类似于 Apache 、 Nginx 等 HTTP 服务器。
3. 接收请求与响应请求 服务器很容易创建,客户端可以使⽤浏览器或终端发送 HTTP 请求,服务器接收请求后返回响应数据。
创建 Node.js 应⽤新建demo⽂件夹作为项⽬根⽬录,在项⽬的根⽬录下创建⼀个叫 server.js 的⽂件。
步骤⼀、引⼊ required 模块
我们使⽤ require 指令来载⼊ http 模块,并将实例化的 HTTP 赋值给变量 http,实例如下:
var http = require("http");
步骤⼆、创建服务器
接下来我们使⽤ http.createServer() ⽅法创建服务器,并使⽤ listen ⽅法绑定 8888 端⼝。 函数通过 request,response 参数来接收和响应数据。
server.js 完整代码如下:
var http = require('http'); http.createServer(function (request, response) { // 发送 HTTP 头部 // HTTP 状态值: 200 : OK // 内容类型: text/plain response.writeHead(200, {'Content-Type': 'text/plain'}); // 发送响应数据 "Hello World" response.end('Hello World\n'); }).listen(8888); // 终端打印如下信息 console.log('Server running at http://127.0.0.1:8888/');
以上代码我们完成了⼀个可以⼯作的 HTTP 服务器。
代码如下图:运⾏ Node.js 应⽤
⽽运⾏ Node.js 程序的常⽤⽅法是,运⾏全局可⽤的命令 node (安装 Node.js 之后)并且传⼊您要执⾏的⽂件的名称。
如果您的 Node.js 主应⽤程序⽂件是 server.js ,则您可以通过键⼊以下来调⽤它:node server.js
以上,你显式地告诉 shell 使⽤ node 运⾏你的脚本,运⾏结果如下:
接下来就可以在⻚⾯上访问http://127.0.0.1:8888/这个⽹址。访问之后获取到该服务器给的响应“Hello World”。
终⽌ Node.js 应⽤
有多种⽅法可以终⽌ Node.js 应⽤程序。
当在控制台中运⾏程序时,可以⽤⼀次 ctrl+C 关闭它。我们这⾥要讨论的是以编程⽅式退出。 process 核⼼模块提供了⼀种⽅便的⽅法,允许您以编程⽅式退出
Node.js 程序: process.exit() 。当 Node.js 运⾏ process.exit() 时,进程⽴即被强制终⽌。
这意味着任何待处理的回调、任何仍在发送的⽹络请求、任何⽂件系统访问、或者正在写⼊ stdout 或 stderr的进程,所有这些都将⽴即被⾮正常地终⽌。Node.js 回调函数
Node.js 异步编程的直接体现就是回调。
异步编程依托于回调来实现,但不能说使⽤了回调后程序就异步化了。
回调函数在完成任务后就会被调⽤, Node 使⽤了⼤量的回调函数, Node 所有 API 都⽀持回调函数。
例如,我们可以⼀边读取⽂件,⼀边执⾏其他命令,在⽂件读取完成后,我们将⽂件内容作为回调函数的参数返回。这样在执⾏代码时就没有阻塞或等待⽂件 I/O 操作。这就⼤⼤提⾼了 Node.js 的性能,可以处理⼤量的并发请求。
回调函数⼀般作为函数的最后⼀个参数出现:function foo1(name, age, callback) { } function foo2(value, callback1, callback2) { }
阻塞代码示例
创建⼀个⽂件 input.txt ,内容如下:
Hello 我是⽂件内的内容!
创建 main.js ⽂件, 代码如下:
var fs = require("fs"); var data = fs.readFileSync('input.txt'); console.log(data.toString()); console.log("程序执⾏结束!");
代码如下图:
运⾏结果如图:
node main.js
⾮阻塞代码实例
保持input.txt不变,将main.js的内容设置为如下内容:
var fs = require("fs"); fs.readFile('input.txt', function (err, data) { if (err) return console.error(err); console.log(data.toString()); }); console.log("程序执⾏结束!");
代码如下图:
运⾏结果如下:
node main.js
以上两个实例我们了解了阻塞与⾮阻塞调⽤的不同。第⼀个实例在⽂件读取完后才执⾏程序。 第⼆个实例我们不需要等待⽂件读取完,这样就可以在读取⽂件时同时执⾏接下来的代码,⼤⼤提⾼了程序的性能。
因此,阻塞是按顺序执⾏的,⽽⾮阻塞是不需要按顺序的,所以如果需要处理回调函数的参数,我们就需要写在回调函数内。
Node.js模块系统package.json 是模块的清单文件,记录了当前模块的基本信息、依赖信息等
属性 解释
version 模块版本
name 模块名称
description 模块描述
main 入口文件
private 如果设置为 true,则可以防止应用程序/软件包被意外地发布到 npm。
scripts 脚本
dependencies 产品依赖
devDependencies 开发依赖
engines nodejs 版本号
browserslist 支持的浏览器
CommonJS模块化早期的Javascript(ECMAScript5)中是没有模块化的,NodeJS推出后,使用的是便是 CommonJS 模块规范。后来ES6出现后才出现了ECMAScript模块化,在node-v12后可以使用 ECMAScript模块化。
CommonJS规定,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可⻅。每个模块内部, module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(即module.exports )是对外的接口。加载某个模块,其实是加载该模块的 module.exports 属性。 require 方法用于加载模块。
导出模块新建modules1.js文件,在该文件中内容如下:
module.exports = { name: 'tom', sayHello() { console.log("hello"); }, };
exports 和 module.exports 的使用
默认情况下: module.exports===exports 为true,相当于如下内容:module.exports = {} exports = module.exports;
require 引入的对象本质上是 module.exports 。这就产生了一个问题,当 module.exports 和 exports 指向的不是同一块内存时, exports 的内容就会失效。
如果要对外暴露属性或方法,就用 exports 就行,要暴露对象(包含了很多属性和方法),就用 module.exports。
导入模块在 Node.js 中,引入一个模块非常简单,如下我们创建一个 module1Test.js 文件并引入 module 模块,代码如下:
let obj = require('./modules1') console.log(obj); obj.sayHello()
代码如下图:
运行结果如下:
node module1Test.js
也可以在导入的同时做解构
let { name, sayHello } = require('./modules1') console.log(name); sayHello()
运行结果如下:
node module1Test.js
1.所有代码都运行在模块作用域,不会污染全局作用域。
2. 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后 再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
3. 模块加载的顺序,按照其在代码中出现的顺序。module对象
每个模块内部,都有一个 module 对象,代表当前模块。
属性名 解释
id 模块的识别符,通常是带有绝对路径的模块文件名。
filename 模块的文件名,带有绝对路径。
loaded 返回一个布尔值,表示模块是否已经完成加载。
parent 返回一个对象,表示调用该模块的模块。
children 返回一个数组,表示该模块要用到的其他模块。
exports 表示模块对外输出的值。require方法
require 引入的对象本质上是 module.exports 。
NodeJS使用CommonJS模块规范,内置的 require 命令用于加载模块文件。 require 命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。 需要注意的是:
1. 如果参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件。比如,
require('/home/marco/foo.js') 将加载 /home/marco/foo.js 。2. 如果参数字符串以“./”开头,则表示加载的是一个位于相对路径(跟当前执行脚本的位置相比)的模块文件。比如, require('./circle') 将加载当前脚本同一目录的circle.js 。
3. 如果参数字符串不以“./“或”/“开头,则表示加载的是一个默认提供的核心模块(位于Node的系统安装目录中),或者一个位于各级node_modules目录的已安装模块(全局安装或局部安装)。
4. require发现参数字符串指向一个目录以后,会自动查看该目录的文件, 然后加载 main 字段指定的入口文件。如果 package.json 文件没有 main 字段,或者根本就没有 package.json 文件,则会加载该目录下的index.js 文件或 index.node 文件。服务端的模块种类
也许你已经注意到,我们已经在之前代码中使用了模块了。像这样:
var http = require("http"); http.createServer(...);
Node.js 中自带了一个叫做 http 的模块,我们在我们的代码中请求它并把返回值赋给一个本地变量。这把我们的本地变量变成了一个拥有所有 http 模块所提供的公共方法的对象。
Node.js 中自带了一个叫做 http 的模块,我们在我们的代码中请求它并把返回值赋给一个本地变量。这把我们的本地变量变成了一个拥有所有 http 模块所提供的公共方法的对象。
模块种类:
内置模块/核心模块,比如上方的http模块或者fs模块。使用 require('内置模块名') 来引入
用户自定义模块,比如上方的modules1.js文件,在该文件中有导出,就可以当做一个模块来使用。使用
require('自定义模块路径') 来引入。一般是以 ./ 或者 ../ 开始的路径所代表的的模块就是用户自定义模块。
第三方模块,第三方模块首先需要下载,然后再引入。比如 require('moment')内置模块: http://nodejs.cn/api/path.html
http 提供HTTP服务器功能。
fs 与文件系统交互。
url 解析url字符串
querystring 解析URL的查询字符串。
util 提供一系列实用小工具。
path 处理文件路径。
crypto提供加密和解密功能,基本上是对OpenSSL的包装。ECMAScript模块
在ES6中每一个模块即是一个文件,在文件中定义的变量,函数,对象在外部是无法获取的。如果你希望外部可以读取模块当中的内容,就必须使用export来对其进行暴露(输出)。
export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系,也就是说外部接口需要用这个接口名来引用。var firstName = 'Michael'; var lastName = 'vicky'; export { firstName, lastName }; //列表导出 export { firstName as first, lastName as last}; //重命名导出 export var a = 3; //导出单个属性 export function multiply(x, y) { return x * y; }; //导出单个属性 //默认导出,一个模块只能有一个默认导出,不能使用 var、let 或 const 用于导出默认值 export default {} export default function foo(){} var a = 1; export a; //报错,因为没有提供对外的接口。应该export var a = 1; 或者export {a}
静态的import 语句用于导入由另一个模块导出的绑定。
import * as person from './person.js' //导入整个模块内容 import {firstName,lastName} from './person.js' //导入多个接口 import {firstName as name} from './person.js' //重命名 import '/modules/my-module.js'; //运行整个模块而不导入任何值 import myDefault from './my-module.js'; // 导入使用export default导出的
异常处理
Node是单线程运行环境,一旦抛出的异常没有被捕获,就会引起整个进程的崩溃。所以, Node的异常处理对于保证系统的稳定运行非常重要。
异常产生原因
一般来说,Node有如下三种方式,会产生异常。
使用throw语句抛出一个错误对象,即抛出异常。
将错误对象传递给回调函数,由回调函数负责发出错误。
通过EventEmitter接口,发出一个error事件解决方案
try-catch一般来说,Node只在很少场合才用try/catch语句,比如使用 JSON.parse 解析JSON文 本。这个结构无法捕获异步运行的代码抛出的异常。
// 可以捕获 try { console.log(a); } catch (err) { console.log("捕获异常:",err); } // 无法捕获 try { setTimeout(()=>{ console.log(a);},0) } catch (err) { console.log("捕获异常:",err); }
回调函数
Node采用的方法,是将错误对象作为第一个参数,传入回调函数。这样就避免了捕获代码与发生错误的代码不在同一个时间段的问题。
let fs = require('fs'); fs.readFile('/foo.txt', function (err, data) { if (err !== null) throw err; console.log(data); });
EventEmitter接口的error事件
发生错误的时候,也可以用EventEmitter接口抛出error事件。
var EventEmitter = require('events').EventEmitter; var emitter = new EventEmitter(); //触发错误 emitter.emit('error', new Error('something bad happened')); //绑定错误监听事件处理程序 emitter.on('error', function(err) { console.error('出错:' + err.message); });
注意和如下代码的区别:
var EventEmitter = require('events').EventEmitter; var emitter = new EventEmitter(); //绑定错误监听事件处理程序 emitter.on('error', function (err) { console.error('出错:' + err.message); }); //触发错误 emitter.emit('error', new Error('something bad happened'));
url模块
提供解析url的工具,一个完整的href结构如下:
url.parse()
将url字符串地址转换为URL对象
let url = require('url') const myURL =url.parse('https://user:pass@sub.example.com:8080/p/a/t/h?que ry=string#hash'); console.log(myURL);
url.format()
构建一个URL字符串
let url = require('url'); let result = url.format({ protocol: 'https', hostname: 'example.com', pathname: '/some/path', query: { page: 1, format: 'json' } }); console.log(result); // => 'https://example.com/some/path?page=1&format=json'
url.resolve(from,to)
合并url字符串
let url = require('url'); url.resolve('/one/two/three', 'four'); // '/one/two/four' url.resolve('http://example.com/', '/one'); // 'http://example.com/one' url.resolve('http://example.com/one', '/two'); // 'http://example.com/two
url.hash
获取或设置URL中hash值
let url = require('url'); const myURL = new URL('https://example.org/foo#bar'); console.log(myURL.hash);// Prints #bar myURL.hash = 'baz'; console.log(myURL.href);// Prints https://example.org/foo#baz
url.host
获取或者设置URL中的host
let url = require('url'); const myURL = new URL('https://example.org:81/foo'); console.log(myURL.host);// Prints example.org:81 myURL.host = 'example.com:82'; console.log(myURL.href);// Prints https://example.com:82/foo
url.hostname
设置或获取URL中的hostname,与host不同的是,hostname不包含端口
let url = require('url'); const myURL = new URL('https://example.org:81/foo'); console.log(myURL.hostname);// Prints example.org
url.origin
获取URL中的origin
let url = require('url'); const myURL = new URL('https://example.org/foo/bar?baz'); console.log(myURL.origin);// Prints https://example.org
url.pathname
获取或设置URL中的路径
let url = require('url'); const myURL = new URL('https://example.org/abc/xyz?123'); console.log(myURL.pathname);// Prints /abc/xyz
url.port
获取或设置URL中的端口号
let url = require('url'); const myURL = new URL('https://example.org:8888'); console.log(myURL.port);// Prints 8888
url.protocol
获取或设置URL的协议
const myURL = new URL('https://example.org'); console.log(myURL.protocol);// Prints https: myURL.protocol = 'ftp'; console.log(myURL.href);// Prints ftp://example.org/
url.search
获取或设置URL的查询字符串
const myURL = new URL('https://example.org/abc?123'); console.log(myURL.search); // Prints ?123 myURL.search = 'abc=xyz'; console.log(myURL.href); // Prints https://example.org/abc?abc=xyz
querystring模块
querystring.parse(str[, sep[, eq[, options]]])
将查询字符串解析为一个对象
let querystring = require('querystring'); let qs = "name=terry&age=12&gender=male" console.log(querystring.parse(qs)); // { name: 'terry', age: '12', gender: 'male' }
querystring.stringify(obj[, sep[, eq[, options]]])
将一个对象序列化为查询字符串
let querystring = require('querystring'); let qs_obj = { name: 'terry', age: '12', gender: 'male' }; console.log(querystring.stringify(qs_obj)) // name=terry&age=12&gender=male
querystring.escape
对查询字符串进行编码
et querystring = require('querystring'); console.log(querystring.escape('name=张三&age=12')); //name%3D%E5%BC%A0%E4%B8%89%26age%3D12
querystring.unescape
对查询字符串进行解码
et querystring = require('querystring'); console.log(querystring.unescape('name%3D%E5%BC%A0%E4%B8%89%26age%3D12')); //name=张三&age=12
path模块
提供了一系列解析路径的工具
path.basename(str[, ext]))
返回路径中最后一部分
let path = require('path') let name = '/Users/briup/Desktop/2021/web2102/nodejs/prepare/3-path.js' console.log(path.basename(name));//3-path.js console.log(path.basename(name, '.js'));//3-path
path.dirname(path)
返回路径中代表文件夹的部分
let path = require('path') let name = '/Users/briup/Desktop/2021/web2102/nodejs/prepare/3-path.js' console.log(path.dirname(name)); // /Users/briup/Desktop/2021/web2102/nodejs/prepare
path.extname(path)
返回路径中文件的后缀名,即路径中最后一个'.'之后的部分。如果一个路径中并不包含'.'或 该路径只包含一个'.' 且这个'.'为路径的第一个字符,则此命令返回空字符串。
let path = require('path') let name = '/Users/briup/Desktop/2021/web2102/nodejs/prepare/3-path.js' console.log(path.extname(name)); // .js let name3 = './Users/briup/Desktop/2021/web2102/nodejs/prepare/3-path.js' console.log(path.extname(name2)); //.js let name2 = './Users/briup/Desktop/2021/web2102/nodejs/prepare/3-path' console.log(path.extname(name3)); //空字符串
path.parse(path)
返回路径字符串的对象。
et path = require('path') let name = '/Users/briup/Desktop/2021/web2102/nodejs/prepare/3-path.js' console.log(path.parse(name)); /* { root: '/', dir: '/Users/briup/Desktop/2021/web2102/nodejs/prepare', base: '3-path.js', ext: '.js', name: '3-path' } */
path.format(pathObject)
从对象中返回路径字符串,和 path.parse 相反。
let path = require('path') console.log(path.format({ root: '/', name: 'file', ext: '.txt' })); // Returns: '/file.txt' console.log(path.format({ root: '/', base: 'file.txt', ext: 'ignored' })); // Returns: '/file.txt' console.log(path.format({ root: '/ignored', dir: '/home/user/dir', base: 'file.txt' })); // Returns: '/home/user/dir/file.txt' console.log(path.format({ dir: './path/dir', base: 'file.txt' })); // Returns: './path/dir/file.txt'
path.isAbsolute(path)
判断参数 path 是否是绝对路径。
let path = require('path') let name = '/Users/briup/Desktop/2021/web2102/nodejs/prepare/3-path.js' console.log(path.isAbsolute(name)); // true
path.join([...paths])
连接多个地址
let path = require('path') console.log(path.join('/foo', 'bar', 'baz/asdf', 'quux', '..')); //'/foo/bar/baz/asdf'
path.normalize(path)
标准化路径,可以识别"." ".."
let path = require('path') console.log(path.normalize('/foo/bar//baz/asdf/quux/..')); // Returns: '/foo/bar/baz/asdf'
path.relative(from, to)
用于将绝对路径转为相对路径,返回从 from 到 to 的相对路径(基于当前工作目录)
let path = require('path') path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb'); // Returns: '../../impl/bbb
path.resolve([...paths])
解析为绝对路径,给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径。
let path = require('path') console.log(path.resolve('/foo/bar', './baz')); // Returns: '/foo/bar/baz' console.log(path.resolve('/foo/bar', '/tmp/file/')); // Returns: '/tmp/file' console.log(path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif')); // If the current working directory is /home/myself/node, // this returns '/home/myself/node/wwwroot/static_files/gif/image.gif'
path.sep
平台的文件路径分隔符,'\' 或 '/'。
let path = require('path') console.log('foo/bar/baz'.split(path.sep)); //linux中 Returns: ['foo', 'bar', 'baz']
path.win32
提供包含上述 path 的方法的对象,不过总是以 win32 兼容的方式交互。
let path = require('path') console.log(path.win32) console.log(path.win32===path) //mac电脑返回false
path.posix
提供包含上述 path 的方法的对象
let path = require('path') console.log(path.posix) console.log(path.posix===path) //mac系统返回true
path.delimiter
路径分隔符,linux操作系统分隔符为":", windows操作系统分隔符为";"
let path = require('path') console.log(path.delimiter); //mac系统输出
util模块
util模块提供了很多工具函数,具体可参照 https://nodejs.org/dist/latestv14.x/docs/api/util.html
或者 http://nodejs.cn/api/util.html#utilcallbackifyoriginalutil.callbackify
将 async 异步函数(或者一个返回值为 Promise 的函数)转换成遵循异常优先的回调⻛格的函数,例如将 (err, value)=> ... 回调作为最后一个参数。 在回调函数中,第一个参数为拒绝的原因(如果 Promise 解决,则为 null ),第二个参数则是解决的值。
const util = require('util'); async function fn() { return 'hello world'; } const callbackFunction = util.callbackify(fn); callbackFunction((err, value) => { if (err) throw err; console.log(value); });
node.js服务器的应用、CommonJs模块化、url模块、querystring模块、path模块、util模块
于 2022-06-11 22:46:56 首次发布