上次教了Promise和async/await,今天來學更實用的技巧!
時間控制和模組化聽起來很高深,但其實就是「定時執行程式」和「把程式碼分檔案管理」。這兩個技巧學會了,你的Node.js程式會變得超專業!
時間控制篇:setTimeout 和 setInterval
setTimeout - 「等一下再執行」
想要程式等幾秒再執行某個動作?用setTimeout就對了!
// 基本用法:3秒後顯示歡迎訊息
const 顯示歡迎訊息 = () => {
setTimeout(() => {
console.log('歡迎使用我們的系統!');
}, 3000); // 3000毫秒 = 3秒
};
顯示歡迎訊息();
實戰應用:API重試機制
網路不穩定時,API呼叫失敗很常見。用setTimeout做重試機制超實用:
// 聰明的API重試
const 呼叫API = async (網址, 重試次數 = 3) => {
for (let i = 0; i < 重試次數; i++) {
try {
console.log(`第${i + 1}次嘗試呼叫API...`);
// 模擬API呼叫(實際上用fetch)
const 結果 = await 模擬API呼叫(網址);
if (結果.成功) {
console.log('API呼叫成功!');
return 結果.資料;
}
} catch (錯誤) {
console.log(`第${i + 1}次失敗:`, 錯誤.message);
// 如果不是最後一次,就等一下再試
if (i < 重試次數 - 1) {
const 等待時間 = 1000 * (i + 1); // 1秒、2秒、3秒
console.log(`等待${等待時間/1000}秒後重試...`);
await new Promise(resolve =>
setTimeout(resolve, 等待時間)
);
}
}
}
throw new Error('API呼叫失敗,已重試多次');
};
// 模擬API呼叫
const 模擬API呼叫 = async (網址) => {
await new Promise(resolve => setTimeout(resolve, 500));
// 30%機率成功
if (Math.random() > 0.7) {
return { 成功: true, 資料: { 訊息: 'API回應成功' } };
} else {
throw new Error('網路連接失敗');
}
};
// 使用方式
呼叫API('https://api.example.com/data')
.then(資料 => console.log('最終結果:', 資料))
.catch(錯誤 => console.log('徹底失敗:', 錯誤.message));
setInterval - 「定期執行」
想要程式定期執行某個動作?setInterval就是你要的!
// 每30秒檢查一次系統狀態
const 開始系統監控 = () => {
const 監控器 = setInterval(async () => {
try {
const 記憶體使用量 = process.memoryUsage();
const 使用量MB = Math.round(記憶體使用量.used / 1024 / 1024);
console.log('系統狀態檢查:', {
時間: new Date().toLocaleString('zh-TW'),
記憶體使用量: `${使用量MB}MB`,
狀態: 使用量MB > 500 ? '警告!記憶體過高' : '正常'
});
// 如果記憶體用量過高,發警告
if (使用量MB > 500) {
console.log('🚨 記憶體使用量過高,請注意!');
}
} catch (錯誤) {
console.log('監控出錯:', 錯誤.message);
}
}, 30000); // 每30秒執行一次
// 回傳停止監控的函式
return () => {
clearInterval(監控器);
console.log('監控已停止');
};
};
// 啟動監控
const 停止監控 = 開始系統監控();
// 需要時可以停止
// 停止監控();
實用範例:自動清理快取
// 簡單的記憶體快取系統
const 快取 = new Map();
// 設定有過期時間的快取
const 設定快取 = (鍵, 值, 存活秒數 = 300) => {
const 過期時間 = Date.now() + (存活秒數 * 1000);
快取.set(鍵, { 值, 過期時間 });
console.log(`快取設定:${鍵} (${存活秒數}秒後過期)`);
};
// 取得快取
const 取得快取 = (鍵) => {
const 項目 = 快取.get(鍵);
if (!項目) {
return null;
}
if (Date.now() > 項目.過期時間) {
快取.delete(鍵);
return null;
}
return 項目.值;
};
// 自動清理過期的快取
const 開始快取清理 = () => {
return setInterval(() => {
const 現在 = Date.now();
let 清理數量 = 0;
for (const [鍵, 項目] of 快取.entries()) {
if (現在 > 項目.過期時間) {
快取.delete(鍵);
清理數量++;
}
}
if (清理數量 > 0) {
console.log(`清理了${清理數量}個過期快取`);
}
}, 60000); // 每分鐘清理一次
};
// 使用範例
設定快取('用戶:123', { 姓名: '小明', 信箱: 'ming@test.com' }, 600);
設定快取('商品:456', { 名稱: 'iPhone', 價格: 30000 }, 300);
const 清理器 = 開始快取清理();
// 測試快取
setTimeout(() => {
console.log('5秒後檢查快取:', 取得快取('用戶:123'));
}, 5000);
模組化篇:讓程式碼井然有序
為什麼要模組化?
想像你的程式碼是一個房子:
- 不模組化:所有東西都塞在客廳,亂七八糟
- 模組化:客廳、廚房、臥室分開,東西好找又整齊
CommonJS 模組系統(Node.js標準)
// utils/計算工具.js - 數學計算模組
const 加法 = (a, b) => a + b;
const 乘法 = (a, b) => a * b;
// 計算商品總價(含稅)
const 計算總價 = (價格, 數量, 稅率 = 0.05) => {
const 小計 = 乘法(價格, 數量);
const 稅額 = 小計 * 稅率;
return 加法(小計, 稅額);
};
// 計算折扣後價格
const 計算折扣價 = (原價, 折扣百分比) => {
return 原價 * (1 - 折扣百分比 / 100);
};
// 把函式匯出給其他檔案使用
module.exports = {
加法,
乘法,
計算總價,
計算折扣價
};
// utils/日期工具.js - 日期處理模組
const 格式化日期 = (日期, 格式 = 'YYYY-MM-DD') => {
const d = new Date(日期);
const 年 = d.getFullYear();
const 月 = String(d.getMonth() + 1).padStart(2, '0');
const 日 = String(d.getDate()).padStart(2, '0');
return 格式
.replace('YYYY', 年)
.replace('MM', 月)
.replace('DD', 日);
};
const 是否為週末 = (日期) => {
const 星期 = new Date(日期).getDay();
return 星期 === 0 || 星期 === 6; // 0是週日,6是週六
};
const 計算天數差 = (開始日期, 結束日期) => {
const 開始 = new Date(開始日期);
const 結束 = new Date(結束日期);
const 差異毫秒 = 結束 - 開始;
return Math.ceil(差異毫秒 / (1000 * 60 * 60 * 24));
};
module.exports = {
格式化日期,
是否為週末,
計算天數差
};
// app.js - 主程式
const { 計算總價, 計算折扣價 } = require('./utils/計算工具');
const { 格式化日期, 是否為週末 } = require('./utils/日期工具');
// 使用計算工具
const 商品價格 = 1000;
const 數量 = 3;
const 總價 = 計算總價(商品價格, 數量, 0.08);
console.log(`商品總價(含8%稅):${總價}元`);
const 折扣價 = 計算折扣價(總價, 10); // 打9折
console.log(`折扣後價格:${折扣價}元`);
// 使用日期工具
const 今天 = 格式化日期(new Date());
console.log(`今天是:${今天}`);
if (是否為週末(new Date())) {
console.log('今天是週末,商品打9折!');
}
實戰:建立一個用戶管理系統
// models/用戶.js - 用戶模型
class 用戶 {
constructor(姓名, 信箱, 密碼) {
this.id = Date.now() + Math.random(); // 簡單的ID生成
this.姓名 = 姓名;
this.信箱 = 信箱;
this.密碼 = 密碼;
this.註冊時間 = new Date();
this.最後登入 = null;
}
取得基本資料() {
return {
id: this.id,
姓名: this.姓名,
信箱: this.信箱,
註冊時間: this.註冊時間
};
}
更新最後登入時間() {
this.最後登入 = new Date();
}
}
// 驗證信箱格式
const 驗證信箱 = (信箱) => {
const 信箱格式 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return 信箱格式.test(信箱);
};
module.exports = { 用戶, 驗證信箱 };
// services/用戶服務.js - 用戶業務邏輯
const { 用戶, 驗證信箱 } = require('../models/用戶');
const 用戶列表 = [];
const 建立用戶 = async (姓名, 信箱, 密碼) => {
// 驗證輸入
if (!姓名 || !信箱 || !密碼) {
throw new Error('姓名、信箱、密碼都不能空白');
}
if (!驗證信箱(信箱)) {
throw new Error('信箱格式不正確');
}
// 檢查信箱是否已存在
const 現有用戶 = 用戶列表.find(用戶 => 用戶.信箱 === 信箱);
if (現有用戶) {
throw new Error('這個信箱已經註冊過了');
}
// 建立新用戶
const 新用戶 = new 用戶(姓名, 信箱, 密碼);
用戶列表.push(新用戶);
console.log(`用戶 ${姓名} 註冊成功!`);
return 新用戶.取得基本資料();
};
const 取得所有用戶 = () => {
return 用戶列表.map(用戶 => 用戶.取得基本資料());
};
const 透過信箱找用戶 = (信箱) => {
const 用戶 = 用戶列表.find(用戶 => 用戶.信箱 === 信箱);
return 用戶 ? 用戶.取得基本資料() : null;
};
const 用戶登入 = (信箱, 密碼) => {
const 用戶 = 用戶列表.find(u => u.信箱 === 信箱 && u.密碼 === 密碼);
if (用戶) {
用戶.更新最後登入時間();
console.log(`${用戶.姓名} 登入成功`);
return 用戶.取得基本資料();
} else {
throw new Error('信箱或密碼錯誤');
}
};
module.exports = {
建立用戶,
取得所有用戶,
透過信箱找用戶,
用戶登入
};
// app.js - 主程式
const { 建立用戶, 取得所有用戶, 用戶登入 } = require('./services/用戶服務');
// 測試用戶系統();
把時間控制和模組化結合:實戰練習
現在我們把學到的技巧結合起來,做一個簡單但實用的系統監控工具:
// monitors/系統監控.js
const 監控記錄 = [];
const 記錄系統狀態 = () => {
const 記憶體 = process.memoryUsage();
const 狀態 = {
時間: new Date().toLocaleString('zh-TW'),
記憶體使用量MB: Math.round(記憶體.used / 1024 / 1024),
CPU使用率: Math.random() * 100, // 模擬CPU使用率
運行時間秒: Math.floor(process.uptime())
};
監控記錄.push(狀態);
// 只保留最近50筆記錄
if (監控記錄.length > 50) {
監控記錄.shift();
}
return 狀態;
};
const 取得監控記錄 = () => 監控記錄;
const 檢查系統健康度 = () => {
if (監控記錄.length === 0) return '無資料';
const 最新狀態 = 監控記錄[監控記錄.length - 1];
if (最新狀態.記憶體使用量MB > 500 || 最新狀態.CPU使用率 > 80) {
return '警告';
} else if (最新狀態.記憶體使用量MB > 300 || 最新狀態.CPU使用率 > 60) {
return '注意';
} else {
return '正常';
}
};
module.exports = {
記錄系統狀態,
取得監控記錄,
檢查系統健康度
};
// services/監控服務.js
const { 記錄系統狀態, 檢查系統健康度 } = require('../monitors/系統監控');
let 監控定時器 = null;
const 開始監控 = (間隔秒數 = 30) => {
if (監控定時器) {
console.log('監控已經在運行中');
return;
}
console.log(`開始系統監控,每${間隔秒數}秒檢查一次`);
監控定時器 = setInterval(() => {
const 狀態 = 記錄系統狀態();
const 健康度 = 檢查系統健康度();
console.log(`[${狀態.時間}] 記憶體: ${狀態.記憶體使用量MB}MB | CPU: ${狀態.CPU使用率.toFixed(1)}% | 健康度: ${健康度}`);
// 如果系統不健康,發出警告
if (健康度 === '警告') {
console.log('🚨 系統資源使用量過高!');
}
}, 間隔秒數 * 1000);
};
const 停止監控 = () => {
if (監控定時器) {
clearInterval(監控定時器);
監控定時器 = null;
console.log('監控已停止');
} else {
console.log('監控並未運行');
}
};
module.exports = {
開始監控,
停止監控
};
// app.js - 整合所有功能
const { 開始監控, 停止監控 } = require('./services/監控服務');
const { 建立用戶, 用戶登入 } = require('./services/用戶服務');
console.log('🚀 Node.js 系統啟動中...');
// 啟動系統監控
開始監控(10); // 每10秒監控一次
// 模擬一些用戶操作
const 模擬用戶操作 = async () => {
try {
await 建立用戶('測試用戶', 'test@example.com', 'password123');
setTimeout(() => {
用戶登入('test@example.com', 'password123');
}, 5000);
} catch (錯誤) {
console.log('用戶操作錯誤:', 錯誤.message);
}
};
模擬用戶操作();
// 30秒後停止監控(這只是示範)
setTimeout(() => {
停止監控();
console.log('系統關閉');
}, 30000);
推薦學習資源
學到這裡,你已經掌握了Node.js的核心技能!想要更進一步的話:
系統化學習 六角學院的Node.js課程會教你更完整的實戰技巧,包括Express框架、資料庫整合、API設計等等。課程是中文教學,很適合台灣的學習者。
下一步該怎麼做?
如果你是完全新手:
- 把這兩篇文章的程式碼都跑過一遍
- 試著修改一些參數,看看會發生什麼
- 考慮上個系統化的課程
如果你已經有一些基礎:
- 試著結合這些技巧做個小專案
- 學習Express框架和資料庫
- 開始建立自己的作品集
記住:程式設計最重要的就是多練習。不要只是看,一定要動手寫!
總結
今天學了Node.js的進階技巧:
- setTimeout:延遲執行,適合做重試機制
- setInterval:定期執行,適合做監控、清理
- 模組化:把程式碼分檔案管理,讓專案更好維護
這些技巧結合起來,你就可以做出很專業的Node.js應用程式了!
下次有機會再跟大家分享Express框架和資料庫的使用技巧。有問題的話歡迎留言討論!
*想要更完整的Node.js學習?立即查看六角學院課程,從基礎到實戰一次搞定!
請先 登入 以發表留言。