Node深入浅出(圣思园教育) 002【学习笔记】

node 的包管理机制和加载机制

npm search xxx
npm view xxx
npm install xxx

nodejs 文件系统操作的 api

Node.jsfs 模块提供同步(Sync)与基于回调/Promise 的异步 API,可以操作本地文件与目录。日常开发中常用的能力包括读取、写入、追加、删除、遍历目录、监听变化等。以下示例基于 CommonJS 语法,若在 ES Module 中使用需要改成 import.

常用 API 速览

  • fs.readFile / fs.promises.readFile:一次性读取文件内容。
  • fs.writeFile / fs.promises.writeFile:写入覆盖文件,自动创建不存在的文件。
  • fs.appendFile / fs.promises.appendFile:在文件末尾追加内容。
  • fs.mkdir / fs.promises.mkdir:创建目录,可级联创建。
  • fs.readdir / fs.promises.readdir:读取目录下的文件名列表。
  • fs.stat / fs.promises.stat:查看文件/目录详细信息(大小、类型、权限等)。
  • fs.access / fs.promises.access:检查路径是否存在以及是否具备指定权限。
  • fs.realpath / fs.promises.realpath:获取符号链接解析后的绝对路径。
  • fs.unlink / fs.promises.unlink:删除文件。
  • fs.rm / fs.promises.rm:删除文件或目录,可配合 recursive/force
  • fs.watch:监听目录或文件的变化。
  • fs.createReadStream / fs.createWriteStream:流式读写适合大文件或管道。

读取与写入

const fs = require('node:fs/promises');

async function readAndWrite() {
  const content = await fs.readFile('./data.txt', 'utf8');
  console.log('原始内容:', content);

  await fs.writeFile('./output.txt', content.toUpperCase(), 'utf8');
  await fs.appendFile(
    './output.txt',
    '\n-- appended at ' + new Date().toISOString()
  );
}

readAndWrite().catch(console.error);

目录遍历与详情

const fs = require('node:fs/promises');
const path = require('node:path');

async function listDir(dir) {
  const entries = await fs.readdir(dir, { withFileTypes: true });
  for (const entry of entries) {
    const fullPath = path.join(dir, entry.name);
    const stats = await fs.stat(fullPath);
    console.log({
      name: entry.name,
      isDirectory: entry.isDirectory(),
      size: stats.size,
      modified: stats.mtime,
    });
  }
}

listDir('./logs').catch(console.error);

确保目录存在

const fs = require('node:fs/promises');

async function ensureDir(dir) {
  await fs.mkdir(dir, { recursive: true }); // 嵌套的方式创建目录
}

ensureDir('./uploads/images').catch(console.error);

权限检查 fs.access

fs.access(path[, mode]) 可用于在实际读写前检查目标路径是否存在以及调用进程对其拥有的权限。mode 默认为 fs.constants.F_OK(仅检测存在性),也可以按位组合 R_OK(可读)、W_OK(可写)、X_OK(可执行)。异步回调用约定是“无错即通过”,Promise 版本会在校验失败时抛出 ENOENT(不存在)、EACCES(无权限)等错误。

const fs = require('node:fs/promises');

async function ensureWritableConfig() {
  try {
    await fs.access('./config/app.json', fs.constants.R_OK | fs.constants.W_OK);
    console.log('配置文件存在且可读写');
  } catch (err) {
    if (err.code === 'ENOENT') {
      console.log('文件不存在,准备创建...');
      await fs.writeFile('./config/app.json', '{}');
      return;
    }
    throw err; // 由调用方决定是否提示权限不足等
  }
}

ensureWritableConfig().catch((err) => {
  console.error('权限检查失败:', err);
});

注意:fs.access 只能反映检查瞬间的状态,紧接着的真实读写仍可能因为条件变化而失败,因此对关键写操作仍需捕获错误。

解析实际路径 fs.realpath

fs.realpath(path[, options]) 会解析相对路径、符号链接、. / .. 段等内容,返回规范化后的绝对路径。默认以 UTF-8 字符串形式返回,可通过 options.encoding 设为 'buffer' 得到 Buffer。Promise 版本会在路径不存在(ENOENT)或链接循环(ELOOP)时抛出错误。

const fs = require('node:fs/promises');

async function resolveUpload(pathLike) {
  const resolved = await fs.realpath(pathLike);
  if (!resolved.startsWith('/var/www/uploads')) {
    throw new Error('访问越界');
  }
  return resolved;
}

resolveUpload('./uploads/../uploads/avatar.jpg')
  .then((absPath) => console.log('真实路径:', absPath))
  .catch(console.error);

fs.realpath.native 使用操作系统提供的原生实现,可能在某些平台更快但行为略有差异(尤其在 Windows UNC 路径上),除非有性能瓶颈一般优先常规版本。

删除文件与目录 fs.rm

fs.rm(target[, options]) 是 Node 14.14+ 推荐的删除 API,可删除单个文件、符号链接,也能在配置 options.recursive === true 时删除非空目录。常见选项:

  • recursive:默认为 false,设为 true 即会递归删除目录树。
  • force:忽略不存在的路径(不抛 ENOENT)并尽量继续删除无法访问的文件,默认 false
  • maxRetries / retryDelay:在 Windows 上处理句柄占用时可自动重试。
const fs = require('node:fs/promises');

async function cleanUploadTmp() {
  await fs.rm('./uploads/tmp', {
    recursive: true,
    force: true, // 不存在也不报错
  });
  console.log('临时目录已清理');
}

cleanUploadTmp().catch((err) => {
  console.error('删除失败:', err);
});

历史的 fs.rmdir(path, { recursive: true }) 已被弃用,建议统一使用 fs.rm;在删除后续会重建的目录时,若存在并发写操作,应结合 fs.mkdir 的错误处理避免竞态。

重命名与移动文件

fs.rename / fs.promises.rename 可以在同一文件系统内对文件或目录进行重命名,目标路径可以包含新的目录结构(若目录不存在需提前创建)。

const fs = require('node:fs/promises');
const path = require('node:path');

async function renameLog() {
  const src = path.resolve('./logs/app.log');
  const destDir = path.resolve('./logs/archive');
  await fs.mkdir(destDir, { recursive: true });

  const dest = path.join(destDir, `app-${Date.now()}.log`);
  await fs.rename(src, dest);
  console.log(`已移动到: ${dest}`);
}

renameLog().catch((err) => {
  if (err.code === 'ENOENT') {
    console.error('源文件不存在');
    return;
  }
  console.error('重命名失败:', err);
});

fs.rename 在不同磁盘或分区之间移动文件可能失败(EXDEV),此时应使用流或 fs.copyFile + fs.unlink 组合来实现复制后删除。

流式处理大文件

const fs = require('node:fs');
const path = require('node:path');

function copyLargeFile(src, dest) {
  return new Promise((resolve, reject) => {
    const readable = fs.createReadStream(src);
    const writable = fs.createWriteStream(dest);

    readable.on('error', reject);
    writable.on('error', reject);
    writable.on('finish', resolve);

    readable.pipe(writable);
  });
}

copyLargeFile(path.resolve('videos/big.mp4'), path.resolve('backup/big.mp4'))
  .then(() => console.log('复制完成'))
  .catch(console.error);

文件流详解

Node.js 的文件流基于核心模块 streamfs.createReadStreamfs.createWriteStream 分别返回可读、可写流对象。它们不会一次性把内容加载进内存,而是在内部维护缓冲区(默认 64 KB)按需读取或写入,适合处理大文件或持续数据流。

  • 常见事件:open(文件描述符已就绪)、data(读取到数据块)、end(可读流结束)、finish(可写流刷新完毕)、error(出现错误)、close(释放资源)。
  • 重要参数:
  • highWaterMark:缓冲区大小,用于控制背压。
  • encoding:可读流默认输出 Buffer,可以设置默认字符编码。
  • flagsmode:控制文件打开方式与权限。
  • 背压(Backpressure):当写入目标处理不过来时,可写流会返回 false,可读流应暂停直到触发 drain 事件,内置的 pipestream/promises.pipeline 会帮你处理。

逐块读取文件并统计字节数

const fs = require('node:fs');

function inspectFile(path) {
  return new Promise((resolve, reject) => {
    let total = 0;
    const reader = fs.createReadStream(path, { highWaterMark: 16 * 1024 });

    reader.on('open', (fd) => {
      console.log('文件描述符:', fd);
    });

    reader.on('data', (chunk) => {
      total += chunk.length;
      console.log('读取块大小:', chunk.length);
    });

    reader.on('end', () => {
      console.log('读取结束,总字节数:', total);
      resolve(total);
    });

    reader.on('error', (err) => {
      console.error('读取失败', err);
      reject(err);
    });
  });
}

inspectFile('./logs/app.log').catch(console.error);

使用 pipeline 串联转换与写入

const fs = require('node:fs');
const zlib = require('node:zlib');
const { pipeline } = require('node:stream/promises');

async function compressLog() {
  await pipeline(
    fs.createReadStream('./logs/app.log', { encoding: 'utf8' }),
    zlib.createGzip({ level: 9 }),
    fs.createWriteStream('./logs/app.log.gz')
  );

  console.log('压缩完成');
}

compressLog().catch(console.error);

pipeline 内置背压处理和错误冒泡,推荐在复杂流组合时使用。处理二进制文件或音视频时,可以改为处理 Buffer,不设置编码即可。

监听文件变化

const fs = require('node:fs');

const watcher = fs.watch('./config.json', (eventType, filename) => {
  console.log('文件变化:', eventType, filename);
});

process.on('SIGINT', () => {
  watcher.close();
  console.log('监听已停止');
});

Promise 风格(.then/.catch)写法示例

如果不想使用 async/await,可以直接对 fs.promises 返回的 Promise 链式调用:

const fs = require('node:fs/promises');

fs.readFile('./input.txt', 'utf8')
  .then((text) => {
    console.log('读取成功:', text);
    return fs.writeFile('./result.txt', text.trim() + '\nProcessed');
  })
  .then(() => fs.stat('./result.txt'))
  .then((stats) => {
    console.log('写入完成,文件大小:', stats.size);
  })
  .catch((err) => {
    console.error('操作失败:', err);
  });

多个操作需要并行时,配合 Promise.all

const fs = require('node:fs/promises');

Promise.all([
  fs.readFile('./a.txt', 'utf8'),
  fs.readFile('./b.txt', 'utf8'),
  fs.readFile('./c.txt', 'utf8'),
])
  .then(([a, b, c]) => fs.writeFile('./merged.txt', [a, b, c].join('\n')))
  .then(() => console.log('并行读取并合并完成'))
  .catch((err) => console.error('并行操作失败:', err));

提示:处理大量异步文件操作时,可结合 Promise.all 或任务队列限制并发,避免同时打开过多文件描述符导致 EMFILE 错误。

文件流的字符流与二进制流对照

在 Java 中会明确区分“字符流(Reader/Writer)”与“字节流(InputStream/OutputStream)”。Node.js 中没有单独的字符流类,所有文件流本质上都是字节流(基于 Buffer)。是否表现为“字符”取决于是否设置了编码。以下示例展示两种常见模式:

文本流(指定编码)

const fs = require('node:fs');

const textReader = fs.createReadStream('./poem.txt', {
  encoding: 'utf8', // 指定编码后 data 事件直接得到字符串
});

textReader.on('data', (chunk) => {
  console.log('文本块:', chunk);
});

textReader.on('end', () => {
  console.log('文本读取完成');
});

encoding 只影响读取出来的数据形态,不会改变底层 Buffer 的读取方式。没有设置编码时,chunk 会是 Buffer 对象。

二进制流(默认 Buffer)

const fs = require('node:fs');

const binaryReader = fs.createReadStream('./images/logo.png'); // 不设置 encoding
const chunks = [];

binaryReader.on('data', (chunk) => {
  chunks.push(chunk);
});

binaryReader.on('end', () => {
  const buffer = Buffer.concat(chunks);
  console.log('PNG 头部签名:', buffer.slice(0, 8));
});

对于二进制数据,通常保持 Buffer 形式处理或写入其他可写流(如网络、压缩流)。

写入字符与二进制

const fs = require('node:fs');

// 写入文本,指定 UTF-8 编码
const textWriter = fs.createWriteStream('./output/hello.txt', {
  encoding: 'utf8',
});
textWriter.write('你好,世界\n');
textWriter.end();

// 写入原始字节
const binaryWriter = fs.createWriteStream('./output/raw.bin');
binaryWriter.write(Buffer.from([0x00, 0xff, 0x10, 0x7a]));
binaryWriter.end();

总结:Node.js 文件流默认处理字节,借助编码即可模拟“字符流”效果;处理大对象或需要精准控制字节时保持 Buffer 更安全。

Buffer 模块详解

Buffer 是 Node.js 在 V8 堆外的一块原生内存,用于处理二进制数据。常见场景有文件读写、网络通信、加密、压缩等。BufferUint8Array 互通,Node 18+ 默认 Buffer 实例也继承自 Uint8Array

  • 创建方式:
  • Buffer.from(string[, encoding])
  • Buffer.from(array|ArrayBuffer)
  • Buffer.alloc(size[, fill[, encoding]])
  • Buffer.allocUnsafe(size)(跳过初始化,性能高但需立即写满)
  • 常见编码:utf8(默认)、base64hexlatin1ascii
  • 推荐搭配 TextEncoder/TextDecoder 做更细粒度的字符处理。

创建与编码转换

const bufUtf8 = Buffer.from('Node.js', 'utf8');
const bufHex = Buffer.from('e4bda0e5a5bd', 'hex'); // “你好”

console.log(bufUtf8); // <Buffer 4e 6f 64 65 2e 6a 73>
console.log(bufHex.toString('utf8')); // 你好

const base64 = bufUtf8.toString('base64');
console.log('Base64:', base64);
console.log('还原:', Buffer.from(base64, 'base64').toString('utf8'));

按字节写入与读取

const buf = Buffer.alloc(8);
buf.writeUInt16BE(0x1234, 0); // 大端
buf.writeUInt16LE(0x5678, 2); // 小端
buf.writeInt32BE(-1, 4);

console.log(buf); // <Buffer 12 34 78 56 ff ff ff ff>
console.log(buf.readUInt16BE(0)); // 4660
console.log(buf.readInt32BE(4)); // -1

切片、拷贝与拼接

const part1 = Buffer.from('Hello ');
const part2 = Buffer.from('World');
const full = Buffer.concat([part1, part2]);

console.log(full.toString()); // Hello World

const slice = full.slice(6); // 共用内存
console.log(slice.toString()); // World

const copyTarget = Buffer.alloc(5);
full.copy(copyTarget, 0, 6);
console.log(copyTarget.toString()); // World

Buffer 与 TypedArray 互操作

const arr = new Uint8Array([1, 2, 3, 4]);
const buf = Buffer.from(arr.buffer); // 共享底层 ArrayBuffer

buf[0] = 99;
console.log(arr[0]); // 99

const view = new Uint32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4);
console.log(view); // Uint32Array(1) [...]

JSON 序列化与 base64 传输

Buffer 默认实现了 toJSON,因此 JSON.stringify(buffer) 会得到 { type: 'Buffer', data: [...] } 结构,反序列化后可以直接丢给 Buffer.from 还原:

const buffer = Buffer.from('你好世界');
const jsonString = JSON.stringify(buffer);
console.log(jsonString); // {"type":"Buffer","data":[228,189,160,229,165,189,228,184,150,231,149,140]}

const jsonObject = JSON.parse(jsonString);
console.log(jsonObject); // { type: 'Buffer', data: [ 228, 189, 160, 229, 165, 189, 228, 184, 150, 231, 149, 140 ] }

const buffer2 = Buffer.from(jsonObject);
console.log(buffer2.toString('utf8')); // 你好世界

在需要通过 JSON 通道传 Buffer 时可以配合 base64 降低体积(JSON 数组会显著增大体积):

const payload = Buffer.from(JSON.stringify({ id: 1, msg: 'hi' }), 'utf8');
const transport = payload.toString('base64');

// 接收方
const decoded = Buffer.from(transport, 'base64');
console.log(JSON.parse(decoded.toString('utf8'))); // { id: 1, msg: 'hi' }

注意:Buffer.allocUnsafe 创建的缓冲区包含旧内存数据,必须在写入后再使用;重复创建大量 Buffer 可能触发 GC 压力,可考虑复用或使用池化策略。

node 的网络模块

net 模块概述

  • net.createServer():创建 TCP 服务器实例,返回 net.Server,通过 connection 事件拿到客户端 socket
  • net.createConnection(options) / net.connect():客户端入口,建立 net.Socket 主动连服务器,可设置 hostporttimeout 等。
  • net.Socket 既是可读可写流,常用事件 dataenderrorclose,常用方法 write()end()setEncoding()setKeepAlive() 等。
  • server.address()server.getConnections(cb) 用于调试监听地址与连接数。

查看本地/远端连接信息

const net = require('net');

const server = net.createServer((socket) => {
  console.log('local port:', socket.localPort);
  console.log('local address:', socket.localAddress);
  console.log('remote port:', socket.remotePort);
  console.log('remote family:', socket.remoteFamily);
  console.log('remote address:', socket.remoteAddress);
});

server.listen(8888, () => console.log('server is listening'));

socket.local* 属性表示当前服务器监听的端口/地址,socket.remote* 则指向客户端信息,调试多客户端接入或排查 NAT 问题很方便。

net 入门示例

// server.js
const net = require('net');

const server = net.createServer((socket) => {
  console.log('client connected:', socket.remoteAddress, socket.remotePort);
  socket.setEncoding('utf8');

  socket.write('Hello from TCP server, type "bye" to quit.\n');

  socket.on('data', (chunk) => {
    const message = chunk.trim();
    console.log('receive:', message);
    if (message.toLowerCase() === 'bye') {
      socket.end('Server closing connection.\n');
    } else {
      socket.write(`Server echo: ${message}\n`);
    }
  });

  socket.on('end', () => console.log('client disconnected'));
  socket.on('error', (err) => console.error('socket error:', err.message));
});

server.on('error', (err) => console.error('server error:', err.message));

server.listen(4000, () => {
  const addr = server.address();
  console.log(`TCP server listening on ${addr.address}:${addr.port}`);
});
// client.js
const net = require('net');

const client = net.createConnection({ host: '127.0.0.1', port: 4000 }, () => {
  console.log('connected to server');
  client.write('ping');
});

client.setEncoding('utf8');

client.on('data', (data) => {
  console.log('server says:', data.trim());
  if (data.includes('echo')) {
    client.write('bye');
  }
});

client.on('end', () => console.log('disconnected from server'));
client.on('error', (err) => console.error('client error:', err.message));

运行 node server.js 后再执行 node client.js 即可看到一问一答的交互流程。

nc(netcat)工具

nc 是类 Unix 系统常见的网络调试工具,可快速建立 TCP/UDP 连接,常用来测试端口监听、传输文本、转发流量。结合上面的服务端,可以在没有 Node 客户端时快速验证:

# 启动 server.js 后,用 nc 充当客户端
nc 127.0.0.1 4000
# 看到提示后输入文本,例如:
ping
hello
bye

nc 会把键盘输入以 TCP 流方式发送给服务器,非常适合排查 net 服务逻辑或协议格式,等价于一个轻量级 TCP 终端。

socket.write 使用说明

socket.write(chunk[, encoding][, callback]) 用于向对端发送数据,是 net.Socket 最常用的输出方法:

  • chunk 可以是 BufferUint8Array 或字符串;如果是字符串,可通过 encoding(默认 utf8)指定编码。
  • 返回值是布尔值,false 表示底层缓冲区已满,需要等待 drain 事件再写入,否则可能触发背压。
  • 可选的 callback 会在数据刷新到底层后调用,适合统计发送完成或错误处理。

常见写法如下:

socket.write('hello', 'utf8', (err) => {
  if (err) {
    console.error('send failed:', err);
    return;
  }
  console.log('send success');
});

if (!socket.write(Buffer.from([0x01, 0x02]))) {
  socket.once('drain', () => {
    console.log('buffer drained, continue writing');
  });
}

当需要结束连接时,可以使用 socket.end() 发送最后一块数据并触发 FIN,比单独 write() 后手动 destroy() 更优雅:

const net = require('net');

const server = net.createServer((socket) => {
  socket.on('data', (msg) => {
    if (msg.toString().trim() === 'bye') {
      socket.end('Goodbye!\n'); // 发送最后一条消息并优雅关闭
      return;
    }
    socket.write('Say "bye" to end connection.\n');
  });
});

server.listen(4000, () => console.log('listening on 4000'));

客户端发送 bye 后,服务器立即返回 Goodbye! 并调用 socket.end(),底层 TCP 会完成 FIN/ACK 握手,远端 end 事件触发,连接正常关闭。

TCP 服务器/客户端完整示例

// tcp-server.js
const net = require('net');

const server = net.createServer((socket) => {
  console.log(`new connection: ${socket.remoteAddress}:${socket.remotePort}`);
  socket.setEncoding('utf8');
  socket.write('Welcome! Type "quit" to close.\n');

  socket.on('data', (chunk) => {
    const msg = chunk.trim();
    if (!msg) return;
    if (msg.toLowerCase() === 'quit') {
      socket.end('Bye!\n');
      return;
    }
    socket.write(`Echo(${new Date().toLocaleTimeString()}): ${msg}\n`);
  });

  socket.on('end', () => console.log('client closed:', socket.remoteAddress));
  socket.on('error', (err) => console.error('socket error:', err.message));
});

server.listen(5000, () => console.log('TCP server listening on port 5000'));
// tcp-client.js
const net = require('net');
const readline = require('readline');

const client = net.createConnection({ host: '127.0.0.1', port: 5000 }, () => {
  console.log('connected to TCP server, type message then Enter');
});

client.setEncoding('utf8');

client.on('data', (data) => {
  console.log(data.trim());
});

client.on('end', () => {
  console.log('server closed connection');
  rl.close();
});

client.on('error', (err) => console.error('client error:', err.message));

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.on('line', (line) => {
  client.write(line);
  if (line.toLowerCase() === 'quit') {
    rl.pause();
  }
});
  1. 先运行 node tcp-server.js,服务器监听 5000 端口。
  2. 在第二个终端运行 node tcp-client.js,通过键盘发送任意消息。
  3. 输入 quit 时客户端会发送终止命令,服务器调用 socket.end() 优雅关闭连接。

UDP 服务器/客户端完整示例

// udp-server.js
const dgram = require('dgram');
const server = dgram.createSocket('udp4');

server.on('message', (msg, rinfo) => {
  console.log(`recv ${msg} from ${rinfo.address}:${rinfo.port}`);
  const reply = Buffer.from(`ack:${msg.toString().toUpperCase()}`);
  server.send(reply, rinfo.port, rinfo.address, (err) => {
    if (err) console.error('send error:', err);
  });
});

server.on('listening', () => {
  const address = server.address();
  console.log(`UDP server listening on ${address.address}:${address.port}`);
});

server.bind(41234);
// udp-client.js
const dgram = require('dgram');
const client = dgram.createSocket('udp4');

client.on('message', (msg) => {
  console.log('server reply:', msg.toString());
  client.close();
});

const payload = Buffer.from('hello udp');
client.send(payload, 41234, '127.0.0.1', (err) => {
  if (err) {
    console.error('send error:', err);
    client.close();
    return;
  }
  console.log('datagram sent');
});
  • UDP 通过 dgram.createSocket 创建无连接套接字,消息以数据报形式发送,可能丢失或乱序,不保证可靠性。
  • 运行 node udp-server.js 后再执行 node udp-client.js,客户端发送一次数据报,服务器收到后立即回传 ack:*,客户端打印回复后关闭。

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://joyjs.cn/archives/4766

(0)
Walker的头像Walker
上一篇 2025年11月24日 02:00
下一篇 2025年11月25日 08:00

相关推荐

  • Go工程师体系课 018【学习笔记】

    API 网关与持续部署入门(Kong & Jenkins) 对应资料目录《第 2 章 Jenkins 入门》《第 3 章 通过 Jenkins 部署服务》,整理 Kong 与 Jenkins 在企业级持续交付中的实战路径。即便零基础,也能顺着步骤搭建出自己的网关 + 持续部署流水线。 课前导览:什么是 API 网关 API 网关位于客户端与后端微服务…

    个人 2025年11月25日
    4600
  • TS珠峰 001【学习笔记】

    课程大纲 搭建 TypeScript 开发环境。 掌握 TypeScript 的基础类型,联合类型和交叉类型。 详细类型断言的作用和用法。 掌握 TypeScript 中函数、类的类型声明方式。 掌握类型别名、接口的作用和定义。 掌握泛型的应用场景,熟练应用泛型。 灵活运用条件类型、映射类型与内置类型。 创建和使用自定义类型。 理解命名空间、模块的概念已经使…

    个人 2025年3月27日
    1.3K00
  • Go工程师体系课 009【学习笔记】

    其它一些功能 个人中心 收藏 管理收货地址(增删改查) 留言 拷贝inventory_srv--> userop_srv 查询替换所有的inventory Elasticsearch 深度解析文档 1. 什么是Elasticsearch Elasticsearch是一个基于Apache Lucene构建的分布式、RESTful搜索和分析引擎,能够快速地…

    个人 2025年11月25日
    5700
  • Node深入浅出(圣思园教育) 001【学习笔记】

    node 从异步编程范式理解 Node.js Node.js 的定位与核心思想 基于 V8 引擎 + libuv 事件驱动库,将 JavaScript 从浏览器带到服务器侧。 采用单线程事件循环处理 I/O,最大化利用 CPU 等待 I/O 的时间片,特别适合高并发、I/O 密集型场景。 “不要阻塞主线程”是设计哲学:尽量把耗时操作交给内核或线程池,回调结果…

    个人 2025年11月24日
    7900
  • 深入理解ES6 008【学习笔记】

    迭代器(Iterator)和生成器(Generator) 这个新特性对于高效的数据处理而言是不可或缺的,你也会发现在语言的其他特性中也都有迭代器的身影:新的for-of循环、展开运算符(...)、甚至连异步编程都可以使用迭代器。 迭代器是一种特殊的对象,它具有一些专门为迭代过程设计的专有接口,所有的迭代器对象都有一个next()方法,每次调用都返回一个结果对…

    个人 2025年3月8日
    94000

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
欢迎🌹 Coding never stops, keep learning! 💡💻 光临🌹