起步 Linux安装node 版本列表:https://nodejs.org/dist/,下载并解压:

xz -d node-v17.2.0-linux-x64.tar.xz tar -xvf node-v17.2.0-linux-x64.tar

然后设置软连接:

ln -s/home/swoole/main/node/bin/npm /usr/local/bin/npm ln -s/home/swoole/main/node/bin/node /usr/local/bin/node

  1. 使用ES6 使用E6语法引入模块,报错如上;依据报错提示,在package.json添加 “type”: “module”,然后再运行js文件,便不再报错。

2.关于Node

每个Node.js进程只有一个主线程在执行程序代码,形成一个执行栈(execution context stack)。 主线程之外,还维护了一个“事件队列”(Event queue)。当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。 主线程代码执行完毕完成后,然后通过Event Loop,也就是事件循环机制,开始到Event Queue的开头取出第一个事件,从线程池中分配一个线程去执行这个事件,接下来继续取出第二个事件,再从线程池中分配一个线程去执行,然后第三个,第四个。主线程不断的检查事件队列中是否有未执行的事件,直到事件队列中所有事件都执行完了,此后每当有新的事件加入到事件队列中,都会通知主线程按顺序取出交EventLoop处理。当有事件执行完毕后,会通知主线程,主线程执行回调,线程归还给线程池。 主线程不断重复上面的第三步。

Node.js 如何处理 ES6 模块 JS有多种格式的模块,一种是 ES6 模块,简称 ESM;另一种是 Node.js 专用的 CommonJS 模块,简称 CJS。这两种模块不兼容。

1.模块差异 ES6 模块和 CommonJS 模块有很大的差异。

语法上面,CommonJS 模块使用require()加载和module.exports输出,ES6 模块使用import和export。

用法上面,require()是同步加载,后面的代码必须等待这个命令执行完,才会执行。import命令则是异步加载,或者更准确地说,ES6 模块有一个独立的静态解析阶段,依赖关系的分析是在那个阶段完成的,最底层的模块第一个执行。

2.Node.js 的区分 Node.js 要求 ES6 模块采用.mjs后缀文件名。也就是说,只要脚本文件里面使用import或者export命令,那么就必须采用.mjs后缀名。Node.js 遇到.mjs文件,就认为它是 ES6 模块,默认启用严格模式,不必在每个模块文件顶部指定“use strict”。

如果不希望将后缀名改成.mjs,可以在项目的package.json文件中,指定type字段为module。

Node.js 要求 ES6 模块采用.mjs后缀文件名。也就是说,只要脚本文件里面使用import或者export命令,那么就必须采用.mjs后缀名。Node.js 遇到.mjs文件,就认为它是 ES6 模块,默认启用严格模式,不必在每个模块文件顶部指定“use strict”。

如果不希望将后缀名改成.mjs,可以在项目的package.json文件中,指定type字段为module。

{ “type”: “module” }

一旦设置了以后,该目录里面的 JS 脚本,就被解释用 ES6 模块。

解释成 ES6 模块

$ node my-app.js

如果这时还要使用 CommonJS 模块,那么需要将 CommonJS 脚本的后缀名都改成.cjs。如果没有type字段,或者type字段为commonjs,则.js脚本会被解释成 CommonJS 模块。

总结为一句话:.mjs文件总是以 ES6 模块加载,.cjs文件总是以 CommonJS 模块加载,.js文件的加载取决于package.json里面type字段的设置。

注意,ES6 模块与 CommonJS 模块尽量不要混用。require命令不能加载.mjs文件,会报错,只有import命令才可以加载.mjs文件。反过来,.mjs文件里面也不能使用require命令,必须使用import。

3.CommonJS 模块加载 ES6 模块 CommonJS 的require()命令不能加载 ES6 模块,会报错,只能使用import()这个方法加载。

(async () => { await import(‘./my-app.mjs’); })();

上面代码可以在 CommonJS 模块中运行。

require()await 4.ES6 模块加载 CommonJS 模块 ES6 模块的import命令可以加载 CommonJS 模块,但是只能整体加载,不能只加载单一的输出项。

// 正确 import packageMain from ‘commonjs-package’; // 报错 import { method } from ‘commonjs-package’;

module.exports 加载单一的输出项,可以写成下面这样。

import packageMain from ‘commonjs-package’; const { method } = packageMain;

5.同时支持两种格式的模块 一个模块同时要支持 CommonJS 和 ES6 两种格式,也很容易。

如果原始模块是 ES6 格式,那么需要给出一个整体输出接口,比如export default obj,使得 CommonJS 可以用import()进行加载。

如果原始模块是 CommonJS 格式,那么可以加一个包装层。

import cjsModule from ‘../index.js’; export const foo = cjsModule.foo;

上面代码先整体输入 CommonJS 模块,然后再根据需要输出具名接口。

你可以把这个文件的后缀名改为.mjs,或者将它放在一个子目录,再在这个子目录里面放一个单独的package.json文件,指明{ type: “module” }。

另一种做法是在package.json文件的exports字段,指明两种格式模块各自的加载入口。

“exports”:{

"require": "./index.js",
"import": "./esm/wrapper.js"

}

上面代码指定require()和import,加载该模块会自动切换到不一样的入口文件。

模块 1.EventEmitter EventEmitter的功能类似前端事件总线,Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。

Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。

//event.js 文件 var EventEmitter = require(‘events’).EventEmitter; var event = new EventEmitter(); event.on(‘some_event’, function() {

console.log('some_event 事件触发'); 

}); setTimeout(function() {

event.emit('some_event'); 

}, 1000);

2.Buffer、TypedArray、ArrayBuffer JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。

在 Node.js 中,Buffer 类是随 Node 内核一起发布的核心库。Buffer 库为 Node.js 带来了一种存储原始数据的方法,可以让 Node.js 处理二进制数据,每当需要在 Node.js 中处理I/O操作中移动的数据时,就有可能使用 Buffer 库。

原始数据存储在 Buffer 类的实例中。一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存。提供了丰富的二进制数据操作方法,如 Buffer.from()、Buffer.alloc()、buffer.toString()、buffer.slice() 等。

TypedArray 是 JavaScript 中的一个抽象基类,用于表示不同类型的二进制数据视图。它包括 Int8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array 和 Float64Array 等。

TypedArray 是基于 ArrayBuffer 的视图,提供了对底层二进制数据的类型化访问。

ArrayBuffer 是 JavaScript 中的一个类,用于表示不可变的二进制数据缓冲区。它是一个固定大小的数组,底层由 C++ 提供支持。

// Buffer 转 ArrayBuffer: const buffer = Buffer.from(‘Hello, world!’, ‘utf-8’); const arrayBuffer = buffer.buffer; //ArrayBuffer 转 Buffer: const arrayBuffer = new ArrayBuffer(13); const uint8Array = new Uint8Array(arrayBuffer); uint8Array.set(new TextEncoder().encode(‘Hello, world!’)); const buffer = Buffer.from(uint8Array); //TypedArray 转 Buffer: const uint8Array = new Uint8Array([72, 101, 108, 108, 111]); const buffer = Buffer.from(uint8Array); //Buffer 转 TypedArray: const buffer = Buffer.from(‘Hello, world!’, ‘utf-8’); const uint8Array = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);

3.Stream(流) Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出)。

Node.js,Stream 有四种流类型:

Readable - 可读操作。 Writable - 可写操作。 Duplex - 可读可写操作. Transform - 操作被写入数据,然后读出结果。

所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:

data - 当有数据可读时触发。 end - 没有更多的数据可读时触发。 error - 在接收和写入过程中发生错误时触发。 finish - 所有数据已被写入到底层系统时触发。

3.1管道流 管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中。

var fs = require(“fs”); // 创建一个可读流 var readerStream = fs.createReadStream(‘input.txt’); // 创建一个可写流 var writerStream = fs.createWriteStream(‘output.txt’); // 管道读写操作 // 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中 readerStream.pipe(writerStream); console.log(“程序执行完毕”);

3.2链式流 链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。

var fs = require(“fs”); var zlib = require(‘zlib’); // 压缩 input.txt 文件为 input.txt.gz fs.createReadStream(‘input.txt’) .pipe(zlib.createGzip()) .pipe(fs.createWriteStream(‘input.txt.gz’)); console.log(“文件压缩完成。”);

4.全局对象 JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。

在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性。

5.其他模块

OS 模块,提供基本的系统操作函数。 Path 模块,提供了处理和转换文件路径的工具。 Net 模块,用于底层的网络通信。提供了服务端和客户端的的操作。 DNS 模块,用于解析域名。 Domain 模块,简化异步代码的异常处理,可以捕捉处理try catch无法捕捉的。

包 1.dotenv库 由于项目不同需求,需要配置不同环境变量,按需加载不同的环境变量文件,使用dotenv,可以完美解决这一问题。

npm install dotenv –save .envprocess.env import ‘dotenv/config’

2.Egg 3.http模块 http 模块主要用于搭建 HTTP 服务端和客户端,使用 HTTP 服务器或客户端功能必须调用 http 模块

var http = require(‘http’); var fs = require(‘fs’); var url = require(‘url’); // 创建服务器 http.createServer( function (request, response) {
// 解析请求,包括文件名 var pathname = url.parse(request.url).pathname; // 输出请求的文件名 console.log(“Request for ” + pathname + “ received.”); // 从文件系统中读取请求的文件内容 fs.readFile(pathname.substr(1), function (err, data) {

  if (err) {
     console.log(err);
     // HTTP 状态码: 404 : NOT FOUND
     // Content Type: text/html
     response.writeHead(404, {'Content-Type': 'text/html'});
  }else{             
     // HTTP 状态码: 200 : OK
     // Content Type: text/html
     response.writeHead(200, {'Content-Type': 'text/html'});    

// 响应文件内容

     response.write(data.toString());        
  }
  //  发送响应数据
  response.end();

});
}).listen(8080); // 控制台会输出以下信息 console.log(‘Server running at http://127.0.0.1:8080/');

4.常用软件包 5.util库

util.inspect(): 将任意 JavaScript 对象转换为字符串形式,以便于调试和输出。 util.format(): 类似于C语言中的printf函数,用于格式化字符串。 util.promisify(): 将基于回调的函数转换为返回Promise的函数,以便于使用 async/await 进行异步编程。 util.isArray(): 判断给定的对象是否是数组。 util.isDate(): 判断给定的对象是否是日期对象。 util.isError(): 判断给定的对象是否是一个Error对象。 util.isPrimitive(): 判断给定的对象是否是原始类型(如字符串、数字、布尔值等)。 util.formatWithOptions(): 类似于util.format(),但是可以指定格式选项。 util.deprecate(): 标记函数已经废弃,并输出警告信息。 util.callbackify(): 将异步函数转换为基于回调的函数。

Egg学习笔记 1.安装egg

npm init egg –type=simple

yarn install

2.编写 Controller // app/controller/home.js const Controller = require(’egg‘).Controller; class HomeController extends Controller { async index() {

this.ctx.body = 'Hello world';

} } module.exports = HomeController;

3.路由映射 // app/router.js module.exports = (app) => { const { router, controller } = app; router.get(’/‘, controller.home.index); };

4.自定义监听的地址 return {

    ...config,
    ...userConfig,
    cluster: {
        listen: {
            port: 7001,
            hostname: '0.0.0.0', // 不建议设置 hostname 为 '0.0.0.0',它将允许来自外部网络和来源的连接,请在知晓风险的情况下使用
            // path: '/var/run/egg.sock',
        },
    }

};

实用函数封装 1.file_get_contents import axios from “axios”; import * as fs from “fs”; import * as https from “https”; /**

  • 读取文件
  • @param url
  • @param options
  • @return {Promise<unknown>} */ function file_get_contents(url, options = {}) { return new Promise((resolve, reject) => { if (url.startsWith(’http‘)) { const config = { url, method: options.method || ’get‘, headers: options.headers || {}, timeout: options.timeout || 5000, httpsAgent: options.verify === false ? new https.Agent({rejectUnauthorized: false}) : undefined, data: options.data || {}, }; axios(config) .then(response => { resolve(response.data); }) .catch(error => { reject(error); }); } else { fs.readFile(url, ’utf8‘, (err, data) => { if (err) { reject(err); } else { resolve(data); } }); } }); } //demo (async () => { // 读取本地文件 const data = await file_get_contents(’./.gitignore‘); console.log(data); // 读取远程链接 const content = await file_get_contents(’https://nicen.cn', { headers: { ‘User-Agent’: ‘Mozilla/5.0’, ‘Accept-Language’: ‘en-US,en;q=0.9’, }, timeout: 5000, verify: false, method: ‘POST’, postData: ‘param1=value1&param2=value2’, }); console.log(content) })(); 2.file_put_contents import * as fs from “fs”; /**
  • 写入文件
  • @param file
  • @param data
  • @param options / function file_put_contents(file, data, options) { options = options || {}; const encoding = options.encoding || ‘utf8’; const flag = options.flag || ‘w’; fs.writeFileSync(file, data, { encoding, flag }); } / 使用 */ file_put_contents(‘example.txt’, ‘Hello again!’, { flag: ‘a’ });
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。