ຖ້າຫາກວ່າທ່ານກໍາລັງຊອກຫາຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບການນໍາໃຊ້ app ຂອງທ່ານ, ທ່ານສາມາດຊອກຫາຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບການນໍາໃຊ້ app ຂອງທ່ານ. ຖ້າຫາກວ່າທ່ານກໍາລັງຊອກຫາຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບການນໍາໃຊ້ app ຂອງທ່ານ, ທ່ານສາມາດຊອກຫາຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບການນໍາໃຊ້ app. ຫຼັງຈາກນັ້ນ, ທ່ານຕິດຕັ້ງ app ຂອງທ່ານໃນການຜະລິດ. ແລະສິ່ງທີ່ສວຍງາມເລີ່ມຕົ້ນ. ຫຼາຍກ່ວາເວລາ, ທັງຫມົດສະແດງໃຫ້ເຫັນວ່າດີ, ແຕ່ໃນເວລາທີ່, ຄໍາຮ້ອງສະຫມັກບໍ່ໄດ້ເຮັດໄດ້. UI breaks. Users ເຮັດໃຫ້ຄໍາສັ່ງ. You wonder what went wrong. ການເຄືອຂ່າຍແມ່ນບໍ່ຄາດຄະເນ, ແລະທ່ານຈໍາເປັນຕ້ອງໄດ້ຮັບອະນຸຍາດໃຫ້ມັນ. ທ່ານຄວນມີຄໍາຖາມທີ່ແຕກຕ່າງກັນ: ສິ່ງທີ່ເກີດຂຶ້ນໃນເວລາທີ່ເຄືອຂ່າຍແມ່ນຍໍາຫຼືບໍ່ມີຄວາມປອດໄພ? ສິ່ງທີ່ເກີດຂຶ້ນໃນເວລາທີ່ backend ແມ່ນຕ່ໍາຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນ? ຂ້າພະເຈົ້າສືບຕໍ່ໄດ້ຮັບການປະທັບໃຈຂອງຂ້າພະເຈົ້າ, ຂ້າພະເຈົ້າຫວັງວ່າຈະໄດ້ເຮັດວຽກຮ່ວມກັບທ່ານອີກເທື່ອຫນຶ່ງ! ໃນບົດຄວາມນີ້, ພວກເຮົາຈະທົດສອບວິທີການທີ່ຈະເຮັດໃຫ້ການຊື້ຄ່ໍາຂອງທ່ານຜະລິດຕະພັນທີ່ເຫມາະສົມໂດຍໃຊ້ບັນຊີລາຍຊື່ ພວກເຮົາຈະ: ffetch ສ້າງ backend ມີ Node.js ແລະ Express ມີບາງ endpoints ສ້າງ frontend ທີ່ກວດສອບ endpoints ທີ່ມີ vanilla JavaScript ໂດຍໃຊ້ API Fetch ເຮັດໃຫ້ backend flaky ເພື່ອ simulate scenarios ໃນໂລກທີ່ແທ້ຈິງ ຊອກຫາວິທີທີ່ການຊອກຫາການຝຶກອົບຮົມສາມາດດໍາເນີນການແລະວິທີການປິ່ນປົວການດໍາເນີນການນີ້ ການນໍາສະເຫນີ ffetch ເພື່ອທົດສອບແລະປັບປຸງການປິ່ນປົວຄວາມຕ້ອງການ fetch ການ Boilerplate ພວກເຮົາຈະສ້າງຕົວແທນຂອງບັນຊີລາຍຊື່ການເຮັດວຽກ multi-user ງ່າຍດາຍ. ການ backend ຈະສະແດງໃຫ້ເຫັນ endpoints RESTful ເພື່ອສ້າງ, ດາວນ໌ໂຫລດ, update, ແລະດາວນ໌ໂຫລດຜູ້ໃຊ້ແລະການເຮັດວຽກ, ແລະໃຫ້ການເຮັດວຽກໃຫ້ຜູ້ໃຊ້. frontend ຈະກວດສອບ backend ເພື່ອໄດ້ຮັບຂໍ້ມູນທີ່ທັນສະໄຫມແລະສະແດງໃຫ້ເຫັນໃຫ້ຜູ້ໃຊ້. ພາສາລາວ ພວກເຮົາຈະນໍາໃຊ້ Node.js ແລະ Express ເພື່ອສ້າງ backend. ພວກເຮົາຍັງຈະນໍາໃຊ້ການເກັບຮັກສາຂໍ້ມູນຢ່າງງ່າຍດາຍໃນອິນເດຍເພື່ອເຮັດໃຫ້ການເຮັດວຽກຢ່າງງ່າຍດາຍ. Here are the user and task models: interface User { id: number; // Unique identifier name: string; // Full name email: string; // Email address } export interface Task { id: number; // Unique identifier title: string; // Short task title description?: string; // Optional detailed description priority: "low" | "medium" | "high"; // Task priority } ພວກເຮົາຈະສ້າງ endpoints ຕໍ່ໄປ: GET /users: ດາວໂຫລດຜູ້ໃຊ້ທັງຫມົດ (ດາວໂຫລດຂະຫນາດໃຫຍ່ຂອງ ID user) POST /users: Create a new user (ດາວໂຫລດ ID ຂອງຜູ້ໃຊ້ທີ່ສ້າງຕັ້ງຂຶ້ນ) GET /users/:id: ຊອກຫາຜູ້ໃຊ້ໂດຍ id PUT /users/:id: ການປັບປຸງຜູ້ໃຊ້ (ດາວໂຫລດຄໍາສັ່ງທີ່ດີ) Delete /users/:id: ດາວໂຫລດໂທລະສັບມືຖື GET /tasks: ດາວນ໌ໂຫລດການເຮັດວຽກທັງຫມົດ (ດາວນ໌ໂຫລດຂະຫນາດໃຫຍ່ຂອງ ID ຂອງການເຮັດວຽກ) GET /tasks/:id: ດາວໂຫລດການເຮັດວຽກໂດຍ id (ດາວໂຫລດ object ການເຮັດວຽກ) POST /tasks: Create a new task (ດາວໂຫລດ ID ຂອງການເຮັດວຽກທີ່ສ້າງຕັ້ງຂຶ້ນ) PUT /tasks/:id: Update a task (ດາວໂຫລດຄໍາສັ່ງທີ່ດີເລີດ) Delete /tasks/:id: ດາວໂຫລດການເຮັດວຽກ GET /users/:userId/tasks: ດາວນ໌ໂຫລດການເຮັດວຽກທັງຫມົດທີ່ໄດ້ຮັບການອະນຸຍາດໃຫ້ຜູ້ໃຊ້ (ດາວນ໌ໂຫລດບັນຊີລາຍລະອຽດການເຮັດວຽກ) POST /users/:userId/tasks/:taskId: ສະຫນັບສະຫນູນການເຮັດວຽກກັບຜູ້ໃຊ້ (ລອກຫາຂໍ້ມູນທີ່ດີ) DELETE /users/:userId/tasks/:taskId: Remove a task from a user ຫນ້າທໍາອິດ ພວກເຮົາຈະສ້າງ SPA ມີສອງການເບິ່ງ: ຫນຶ່ງສໍາລັບການສະບັບຜູ້ໃຊ້ແລະຫນຶ່ງສໍາລັບຜູ້ໃຊ້ພິເສດ. ການສະບັບຜູ້ໃຊ້ສະແດງໃຫ້ເຫັນຊື່ຜູ້ໃຊ້ແລະຈໍານວນຂອງການເຮັດວຽກທີ່ໄດ້ຮັບອະນຸຍາດໃຫ້ພວກເຂົາ. ການຄລິກໃສ່ຜູ້ໃຊ້ຈະໃຫ້ທ່ານໄປຫາສະບັບຜູ້ໃຊ້, ເຊິ່ງສະແດງໃຫ້ເຫັນຂໍ້ມູນຂອງຜູ້ໃຊ້ແລະການເຮັດວຽກຂອງພວກເຂົາ. ແລະຈາກສະບັບຜູ້ໃຊ້, ພວກເຮົາສາມາດໄປຫາສະບັບຜູ້ໃຊ້. ພວກເຮົາຈະນໍາໃຊ້ການຄົ້ນຄວ້າເພື່ອໄດ້ຮັບຂໍ້ມູນທີ່ທັນສະໄຫມຈາກ backend. ໃນເວລາທີ່ 3 ວິນາທີ, ພວກເຮົາຈະເຮັດການຄົ້ນຄວ້າກັບ backend ເພື່ອໄດ້ຮັບຂໍ້ມູນທີ່ທັນສະໄຫມສໍາລັບການຊອກຫາທີ່ທັນສະໄຫມແລະປັບປຸງ UI ໂດຍທົ່ວໄປ. ສໍາລັບການຊອກຫາ userlist, ພວກເຮົາຈະເຮັດຄວາມຕ້ອງການທີ່ຈະ ເພື່ອໄດ້ຮັບ ID ຂອງຜູ້ໃຊ້ທັງຫມົດ, ຫຼັງຈາກນັ້ນສໍາລັບທຸກຜູ້ໃຊ້, ພວກເຮົາຈະເຮັດຄວາມຕ້ອງການທີ່ຈະ ເພື່ອຊອກຫາຂໍ້ມູນຂອງເຂົາເຈົ້າ, ແລະ ຊື່ຫຍໍ້ຂອງ : The number of tasks assigned to them GET /users GET /users/:id GET /users/:id/tasks ສໍາລັບການຊອກຫາຜູ້ໃຊ້, ພວກເຮົາມີຄວາມຕ້ອງການທີ່ຈະ ເພື່ອໄດ້ຮັບຂໍ້ມູນຂອງຜູ້ໃຊ້, ແລະ ເພື່ອໄດ້ຮັບ id ຂອງການເຮັດວຽກທີ່ໄດ້ຮັບການອະນຸຍາດໃຫ້ພວກເຂົາ. ຫຼັງຈາກນັ້ນສໍາລັບທຸກ ID ຂອງການເຮັດວຽກ, ພວກເຮົາມີຄວາມຕ້ອງການທີ່ຈະ ດາວນ໌ໂຫລດລາຍລະອຽດຂອງການເຮັດວຽກ GET /users/:id GET /users/:id/tasks GET /tasks/:id ດາວນ໌ໂຫລດ GitHub You can find the complete code for this example in the accompanying . ລະຫັດ QR ເນື່ອງຈາກຂະຫນາດຂອງ boilerplate, ຂໍຂອບໃຈກັບ repo ສໍາລັບລະຫັດທັງຫມົດ. ທັງຫມົດຂອງບົດຄວາມຈະຂໍຂອບໃຈກັບແຜ່ນໃນ repo. repo ມີລະຫັດ backend ແລະ frontend. folder, ແລະ frontend ແມ່ນໃນ folder. ຖ້າຫາກວ່າທ່ານ clone repo, ດໍາເນີນການ ຫຼັງຈາກນັ້ນ, ທ່ານສາມາດຕິດຕັ້ງບັນຊີລາຍລະອຽດໃນບັນຊີລາຍລະອຽດທັງສອງ. ໃນ The folder, ແລະ frontend ກັບ ໃນ The folder. frontend ຈະໄດ້ຮັບການບໍລິການໃນ ທີ່ຜ່ານມາ: Backend at . backend frontend npm install npm run dev backend npm run dev frontend http://localhost:5173 http://localhost:3000 ຫຼັງຈາກທີ່ທ່ານໄດ້ເຮັດວຽກທັງຫມົດແລະທັງ backend ແລະ frontend ຂອງທ່ານກໍາລັງເຮັດວຽກ, ທ່ານສາມາດເປີດ browser ຂອງທ່ານແລະໄປ ດາວນ໌ໂຫລດ App In Action: http://localhost:5173 ການພັດທະນາ ຖ້າ ຫາກ ວ່າ ທ່ານ Navigate , ທ່ານຄວນຈະເບິ່ງສິ່ງທຸກຢ່າງເຮັດວຽກຢ່າງງ່າຍດາຍ. ຖ້າຫາກວ່າທ່ານເພີ່ມຜູ້ໃຊ້ໃຫມ່ກັບ http://localhost:5173 curl -X POST http://localhost:3000/users \ -H "Content-Type: application/json" \ -d '{"name": "John Doe", "email": "john@example.com"}' ທ່ານຄວນຈະເບິ່ງຜູ້ໃຊ້ທີ່ສະແດງໃຫ້ເຫັນໃນຮູບພາບການຊອກຫາຜູ້ໃຊ້ໃນໄລຍະ 3 ວິນາທີ. ມີຄວາມປອດໄພທີ່ຈະດາວໂຫລດ app ແລະເພີ່ມຜູ້ໃຊ້ແລະການເຮັດວຽກເພີ່ມເຕີມ. ປະສິດທິພາບຫຼາຍທີ່ສຸດ, ທັງຫມົດຈະເຮັດວຽກດີ. ຂ້າພະເຈົ້າສືບຕໍ່ໄດ້ຮັບການປະທັບໃຈສໍາລັບລູກຄ້າຂອງພວກເຮົາ - ຂ້າພະເຈົ້າຫວັງວ່າຈະໄດ້ເຮັດວຽກຮ່ວມກັບທ່ານອີກເທື່ອຫນຶ່ງ! ວິທີການ Simulating Network Errors ຖ້າຫາກວ່າທ່ານກໍາລັງຊອກຫາຄໍາຮ້ອງສະຫມັກຂອງພວກເຮົາ, ກະລຸນາຕິດຕໍ່ຄໍາຮ້ອງສະຫມັກຂອງພວກເຮົາໂດຍບໍ່ເສຍຄ່າກັບຄໍາຮ້ອງສະຫມັກຂອງພວກເຮົາໂດຍບໍ່ເສຍຄ່າໂດຍບໍ່ເສຍຄ່າໂດຍບໍ່ເສຍຄ່າໂດຍບໍ່ເສຍຄ່າໂດຍບໍ່ເສຍຄ່າໂດຍບໍ່ເສຍຄ່າໂດຍບໍ່ເສຍຄ່າ. ທ່ານສາມາດຊອກຫາ flaky middleware ໃນ ເອກະສານ. ນີ້ແມ່ນລະຫັດ: backend/src/middleware/flaky.ts import { Request, Response, NextFunction } from 'express'; export function flaky(req: Request, res: Response, next: NextFunction) { // Randomly fail requests with a 20% chance if (Math.random() < 0.2) { return res.status(500).json({ error: 'Random failure' }); } // Add random delay up to 2 seconds const delay = Math.random() * 2000; setTimeout(next, delay); } ຫຼັງຈາກນັ້ນ, ພວກເຮົາສາມາດນໍາໃຊ້ intermediate ນີ້ໃນ app Express ຂອງພວກເຮົາ. ທ່ານສາມາດຊອກຫາລະຫັດໃນ ຂໍຂອບໃຈວ່າທ່ານກໍາລັງຊອກຫາຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບເວັບໄຊທ໌ຂອງພວກເຮົາ backend/src/index.ts ... import { flaky } from './middleware/flaky'; ... app.use(cors()); app.use(express.json()); app.use(flaky); // Use the flaky middleware ລະຫັດການນີ້ແມ່ນໃນ ສາຍຂອງ repo, ດັ່ງນັ້ນທ່ານສາມາດກວດສອບກັບ . network-errors git checkout network-errors ໃນປັດຈຸບັນ, ຖ້າຫາກວ່າທ່ານເລີ່ມຕົ້ນ backend ຂອງທ່ານແລະດາວໂຫລດ frontend ຂອງທ່ານ, ທ່ານຈະເລີ່ມຕົ້ນຊອກຫາສິ່ງທີ່ນິຍົມຫຼາຍ. console ຈະມີບັນຫາ. ແລະນີ້ແມ່ນເວລາທີ່, ຖ້າຫາກວ່າທ່ານບໍ່ມີ, ທ່ານຈໍາເປັນຕ້ອງເລີ່ມຕົ້ນຄວາມຄິດເຫັນກ່ຽວກັບວິທີການປິ່ນປົວຄວາມຜິດພາດເຫຼົ່ານີ້ຢ່າງງ່າຍດາຍ. undefined ປະເພດ scenarios ຫນ້າທໍາອິດ, ກະລຸນາຊອກຫາສິ່ງທີ່ສາມາດດໍາເນີນການຢ່າງງ່າຍດາຍແລະວິທີທີ່ພວກເຮົາສາມາດປິ່ນປົວມັນ: ການທົດສອບເຄືອຂ່າຍ intermittent: ຄໍາຮ້ອງສະຫມັກສາມາດທົດສອບໂດຍບໍ່ເສຍຄ່າ, ດັ່ງນັ້ນໃນຄວາມຜິດພາດໃດກໍ່ຕາມ, ພວກເຮົາຈໍາເປັນຕ້ອງທົດສອບພວກເຂົາອີກເທື່ອຫນຶ່ງຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນ. ຖ້າຫາກວ່າທ່ານກໍາລັງຊອກຫາຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບການຄົ້ນຄວ້າຂອງພວກເຮົາ, ພວກເຮົາມີຄວາມຮູ້ສຶກວ່າທ່ານກໍາລັງຊອກຫາຂໍ້ມູນເພີ່ມເຕີມ. ຖ້າຫາກວ່າທ່ານກໍາລັງຊອກຫາຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບການຄົ້ນຄວ້າຂອງພວກເຮົາ, ພວກເຮົາມີຄວາມຮູ້ສຶກວ່າທ່ານກໍາລັງຊອກຫາຂໍ້ມູນເພີ່ມເຕີມ. ນອກເຫນືອໄປຈາກນີ້, ຖ້າຫາກວ່າຜູ້ໃຊ້ navigates ກັບການຊອກຫາທີ່ແຕກຕ່າງກັນໃນເວລາທີ່ການຊອກຫາຈາກການຊອກຫາທີ່ຜ່ານມາຍັງກໍາລັງຊອກຫາ, ພວກເຮົາສາມາດໄດ້ຮັບການຕອບສະຫນອງສໍາລັບການຊອກຫາທີ່ຜ່ານມາຫຼັງຈາກນັ້ນພວກເຮົາກໍາລັງຊອກຫາຈາກການຊອກຫາທີ່ຜ່ານມາ. ນອກເຫນືອໄປຈາກນີ້ພວກເຮົາມີຄວາມສາມາດສ້າງສະຖານທີ່ UI inconsistent. ພວກເຮົາມີຄວາມຕ້ອງການທີ່ຈະຮັບປະກັນວ່າພຽງແຕ່ການຕອບສະຫນອງສໍາລັບການຊອກຫາທີ່ຜ່ານມາແມ່ນຖືກນໍາໃຊ້ເພື່ອປັບປຸງ UI, ດັ່ງນັ້ນ, ໃນເວລາທີ່ພວກເຮົາມີການຊອກຫາທີ່ແຕກຕ່າງກັນ, ພວກເຮົາມີຄວາມຕ້ອງການທີ່ແຕກຕ່າງກັນ. ຖ້າຫາກວ່າຄໍາຮ້ອງສະຫມັກທີ່ໄດ້ຮັບຜົນສໍາເລັດໃນເວລາທີ່ຫນຶ່ງ, ແຕ່ຫຼັງຈາກນັ້ນບໍ່ໄດ້ຮັບຜົນສໍາເລັດໃນໄລຍະການຄົ້ນຄວ້າທີ່ຜ່ານມາ, ພວກເຮົາບໍ່ຕ້ອງການສະແດງໃຫ້ເຫັນຄວາມເປັນສ່ວນຕົວຂອງຄວາມຜິດພາດກັບຜູ້ໃຊ້. ພວກເຮົາສາມາດ cache ຄໍາຮ້ອງສະຫມັກທີ່ໄດ້ຮັບຜົນສໍາເລັດເພື່ອໃຫ້ຜູ້ໃຊ້ບໍ່ເຂົ້າໃຈກັບທຸກສິ່ງທຸກຢ່າງໃນເຄືອຂ່າຍ. ພວກເຮົາມີຄວາມຕ້ອງການທີ່ຈະປິ່ນປົວ scenarios ທີ່, ກະລຸນາ, ພວກເຮົາມີຄວາມຊອກຫາຜູ້ໃຊ້ທີ່ໄດ້ຮັບການຫຼຸດຜ່ອນໃນ backend. ພວກເຮົາມີຄວາມຕ້ອງການທີ່ຈະປິ່ນປົວຄວາມຜິດພາດ 404 ມີຄວາມສຸກແລະ navigate back to the userlist view, ຫຼືຫຼັງຈາກນັ້ນຫຼັງຈາກນັ້ນສະແດງໃຫ້ເຫັນບັນຫາທີ່ບໍ່ໄດ້ຮັບການຊອກຫາ. ນອກເຫນືອໄປຈາກນີ້, ພວກເຮົາມີຄວາມຕ້ອງການທີ່ຈະປິ່ນປົວສະຖາບັນທີ່ backend ແມ່ນບໍ່ສາມາດເຂົ້າເຖິງຫຼືບໍ່ສາມາດເຂົ້າເຖິງ. ພວກເຮົາມີຄວາມຕ້ອງການທີ່ຈະສະແດງໃຫ້ເຫັນຄວາມເປັນຈິງທົ່ວໂລກກັບຜູ້ໃຊ້ແລະສາມາດປິ່ນປົວຄໍາຮ້ອງສະຫມັກຫຼັງຈາກນັ້ນ. ພວກເຮົາ ກໍາ ລັງເຮັດທຸລະກິດໃນ 2012. ພວກເຮົາແມ່ນບໍລິສັດທີ່ໃຫຍ່ທີ່ສຸດ ສໍາ ລັບຜູ້ໃຫ້ບໍລິການລູກຄ້າຂອງພວກເຮົາ. ພວກເຮົາແມ່ນບໍລິສັດທີ່ໃຫຍ່ທີ່ສຸດ ສໍາ ລັບຜູ້ໃຫ້ບໍລິການລູກຄ້າຂອງພວກເຮົາ. ການປິ່ນປົວຄວາມຜິດພາດກັບ Vanilla Fetch ນີ້, ເຊັ່ນດຽວກັນກັບສິ່ງຫຼາຍໃນ JavaScript (ຫຼື TypeScript), ທ່ານມີສອງການເລືອກໃນການປິ່ນປົວ scenarios ນີ້. ທ່ານສາມາດຂຽນ Functions utility ຂອງທ່ານເອງເພື່ອບັນລຸ API Fetch ແລະເພີ່ມການປິ່ນປົວບັນຫາທີ່ຕ້ອງການ, ຫຼືທ່ານສາມາດເລືອກໂທລະສັບມືຖືທີ່ເຮັດວຽກນີ້ສໍາລັບທ່ານ. ພວກເຮົາຈະເລີ່ມຕົ້ນໂດຍ implementing everything ourselves. ລະຫັດແມ່ນຢູ່ໃນ ສາຍຂອງ repo, ດັ່ງນັ້ນທ່ານສາມາດກວດສອບກັບ . native-fetch git checkout native-fetch ສິ່ງທີ່ຈໍາເປັນຕ້ອງໄດ້ຮັບການ ການຕັດສິນໃຈຂອງການຕັດສິນໃຈໃນ poller.ts ສໍາລັບແຕ່ລະຄໍາຖາມ, ສ້າງ AbortController ໃຫມ່, ແລະຫຼຸດຜ່ອນທີ່ຜ່ານມາ. Wrap ກວດສອບການໂທໃນ Function Retry-and-timeout. ໃນປັດຈຸບັນ, ການປັບປຸງ cache ແລະນໍາໃຊ້ມັນສໍາລັບ rendering. ໃນກໍລະນີທີ່ບໍ່ໄດ້ຮັບການປິ່ນປົວ, ການປິ່ນປົວໃນເວລາທີ່ຕ້ອງການ, ແລະການປິ່ນປົວ timeouts / ການປິ່ນປົວຢ່າງງ່າຍດາຍ. ພາສາລາວ ເອກະຊົນບໍລິການຂົນສົ່ງ poller.ts // Cache for responses const cache: Record<string, any> = {}; // AbortController for cancelling requests let currentController: AbortController | undefined; // Helper: fetch with retries and timeout async function fetchWithRetry(url: string, options: RequestInit = {}, retries = 2, timeout = 3000): Promise<any> { for (let attempt = 0; attempt <= retries; attempt++) { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), timeout); try { const res = await fetch(url, { ...options, signal: controller.signal }); clearTimeout(timer); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); return data; } catch (err) { clearTimeout(timer); if (attempt === retries) throw err; } } } // Cancel all previous requests function cancelRequests() { if (currentController) currentController.abort(); currentController = new AbortController(); } export async function fetchUserListData() { cancelRequests(); // Use cache if available if (cache.userList) return cache.userList; try { if (!currentController) throw new Error('AbortController not initialized'); const userIds = await fetchWithRetry('http://localhost:3000/users', { signal: currentController!.signal }); const users = await Promise.all(userIds.map((id: number) => fetchWithRetry(`http://localhost:3000/users/${id}`, { signal: currentController!.signal }))); const taskCounts = await Promise.all(userIds.map((id: number) => fetchWithRetry(`http://localhost:3000/users/${id}/tasks`, { signal: currentController!.signal }).then((tasks: any[]) => tasks.length))); cache.userList = { users, taskCounts }; return cache.userList; } catch (err) { // fallback to cache if available if (cache.userList) return cache.userList; throw err; } } export async function fetchUserDetailsData(userId: number) { cancelRequests(); const cacheKey = `userDetails_${userId}`; if (cache[cacheKey]) return cache[cacheKey]; try { if (!currentController) throw new Error('AbortController not initialized'); const user = await fetchWithRetry(`http://localhost:3000/users/${userId}`, { signal: currentController!.signal }); const taskIds = await fetchWithRetry(`http://localhost:3000/users/${userId}/tasks`, { signal: currentController!.signal }); const tasks = await Promise.all(taskIds.map((id: number) => fetchWithRetry(`http://localhost:3000/tasks/${id}`, { signal: currentController!.signal }))); cache[cacheKey] = { user, tasks }; return cache[cacheKey]; } catch (err) { if (cache[cacheKey]) return cache[cacheKey]; throw err; } } ຂໍຂອບໃຈ ໃນຖານະເປັນ all fetch logic ໃນປັດຈຸບັນ . ໃນກໍລະນີການນໍາໃຊ້ຢ່າງງ່າຍດາຍຂອງພວກເຮົາ, ມັນສາມາດໄດ້ຮັບການປິ່ນປົວ, ແຕ່ຍັງນີ້, ພວກເຮົາມີຄວາມຕ້ອງການທີ່ຈະເພີ່ມຈໍານວນຫຼາຍຂອງລະຫັດ boilerplate ເພື່ອປິ່ນປົວຄວາມຜິດພາດ, retries, timeouts, ການປິ່ນປົວແລະ caching. ແລະນີ້ແມ່ນພຽງແຕ່ສໍາລັບການປະຕິບັດການອ່ານ. ສະແດງໃຫ້ເຫັນວ່າທ່ານຕ້ອງມີລະຫັດເພີ່ມເຕີມຫຼາຍເພື່ອປິ່ນປົວການສ້າງ, ການປັບປຸງ, ແລະດາວໂຫລດຜູ້ໃຊ້, ຄໍາຮ້ອງສະຫມັກ, ແລະການບໍລິການ. api.ts poller.ts ຖ້າຫາກວ່າທ່ານກໍາລັງໃຊ້ app ໃນປັດຈຸບັນ, ທ່ານຄວນຮູ້ວ່າມັນເຮັດວຽກດີກວ່າຫຼາຍ. UI ແມ່ນສະດວກສະບາຍຫຼາຍແລະບໍ່ເສຍຄ່າຢ່າງກວ້າງຂວາງ. ທ່ານສາມາດເບິ່ງບັນຫາບາງຢ່າງໃນ console, ແຕ່ພວກເຂົາເຈົ້າໄດ້ຮັບການປິ່ນປົວຢ່າງງ່າຍດາຍແລະບໍ່ມີຜົນປະໂຫຍດຫຼາຍສໍາລັບປະສົບການຜູ້ໃຊ້. ຂັ້ນຕອນຂອງການປິ່ນປົວນີ້ More boilerplate code: ພວກເຮົາຈໍາເປັນຕ້ອງຂຽນລະຫັດຫຼາຍເພື່ອປິ່ນປົວຄວາມຜິດພາດ, retries, timeouts, cancellations, ແລະ caching. This can quickly become messy and difficult to maintain. ບໍ່ຖືກນໍາໃຊ້ຢ່າງກວ້າງຂວາງ: ລະຫັດແມ່ນເຊື່ອມຕໍ່ຢ່າງກວ້າງຂວາງກັບກໍລະນີການນໍາໃຊ້ພິເສດຂອງພວກເຮົາແລະບໍ່ຖືກນໍາໃຊ້ຢ່າງກວ້າງຂວາງສໍາລັບໂຄງການຫຼືສະຖານທີ່ອື່ນໆ. ຄຸນນະສົມບັດທີ່ຈໍາກັດ: ຄຸນນະສົມບັດການປິ່ນປົວພຽງແຕ່ scenarios ຄວາມຜິດພາດພື້ນຖານ. ຄຸນນະສົມບັດທີ່ເຫມາະສົມຫຼາຍເຊັ່ນ backoff ອັດຕະໂນມັດ, circuit breakers, ຫຼືການປິ່ນປົວຄວາມຜິດພາດທົ່ວໂລກຈະຕ້ອງການຄຸນນະສົມບັດເພີ່ມເຕີມ. ການນໍາໃຊ້ ສໍາລັບການຄຸ້ມຄອງ Fetch ທີ່ດີທີ່ສຸດ ລະຫັດ QR ລະຫັດ QR ສໍາລັບການປິ່ນປົວຄວາມເປັນສ່ວນຕົວຂອງການປິ່ນປົວການຊອກຫາ custom ຂອງພວກເຮົາ, I wrote a library called ມັນເປັນໂທລະສັບມືຖືຂະຫນາດນ້ອຍແລະງ່າຍທີ່ກວມເອົາ API Fetch ແລະສະຫນອງວິທີງ່າຍດາຍແລະ declarative ເພື່ອປິ່ນປົວຄວາມຜິດພາດ, reries, timeouts, cancellations, ແລະຄຸນນະສົມບັດອື່ນໆ. ffetch ດາວນ໌ໂຫລດ Fetch Logic . ທ່ານສາມາດຊອກຫາລະຫັດໃນ ສາຍຂອງ repo, ດັ່ງນັ້ນທ່ານສາມາດກວດສອບກັບ . ffetch ffetch git checkout ffetch ດາວນ໌ໂຫລດ Install ໃນ The ລະຫັດ QR ffetch frontend npm install @gkoos/ffetch ຫຼັງຈາກນັ້ນ, ພວກເຮົາສາມາດ rewriting ຂອງພວກເຮົາ ການນໍາໃຊ້ File : poller.ts ffetch import createClient from '@gkoos/ffetch'; // Cache for responses const cache: Record<string, any> = {}; // Create ffetch client const api = createClient({ timeout: 3000, retries: 2, }); function cancelRequests() { api.abortAll(); } export async function fetchUserListData() { cancelRequests(); if (cache.userList) return cache.userList; try { const userIds = await api('http://localhost:3000/users').then(r => r.json()); const users = await Promise.all( userIds.map((id: number) => api(`http://localhost:3000/users/${id}`).then(r => r.json())) ); const taskCounts = await Promise.all( userIds.map((id: number) => api(`http://localhost:3000/users/${id}/tasks`).then(r => r.json()).then((tasks: any[]) => tasks.length)) ); cache.userList = { users, taskCounts }; return cache.userList; } catch (err) { if (cache.userList) return cache.userList; throw err; } } export async function fetchUserDetailsData(userId: number) { cancelRequests(); const cacheKey = `userDetails_${userId}`; if (cache[cacheKey]) return cache[cacheKey]; try { const user = await api(`http://localhost:3000/users/${userId}`).then(r => r.json()); const taskIds = await api(`http://localhost:3000/users/${userId}/tasks`).then(r => r.json()); const tasks = await Promise.all( taskIds.map((id: number) => api(`http://localhost:3000/tasks/${id}`).then(r => r.json())) ); cache[cacheKey] = { user, tasks }; return cache[cacheKey]; } catch (err) { if (cache[cacheKey]) return cache[cacheKey]; throw err; } } ລະຫັດແມ່ນງ່າຍດາຍຫຼາຍແລະງ່າຍດາຍທີ່ຈະອ່ານ. ພວກເຮົາບໍ່ຈໍາເປັນຕ້ອງຊອກຫາສໍາລັບການ retries, timeouts, ຫຼືການປິ່ນປົວ. ພວກເຮົາພຽງແຕ່ສ້າງລູກຄ້າທີ່ມີຄໍາຮ້ອງສະຫມັກທີ່ຕ້ອງການແລະນໍາໃຊ້ມັນເພື່ອເຮັດໃຫ້ຄໍາຮ້ອງສະຫມັກ ffetch ຜົນປະໂຫຍດອື່ນໆຂອງການນໍາໃຊ້ ffetch ການປິ່ນປົວ circuit breaker: ການປິ່ນປົວ endpoint ອັດຕະໂນມັດຫຼັງຈາກການປິ່ນປົວການປິ່ນປົວ ອັດຕະໂນມັດ Backoff Exponential ສໍາ ລັບ retries: ການຂະຫຍາຍຕົວເວລາໃນລະຫວ່າງ retries ການປິ່ນປົວຄວາມຜິດພາດທົ່ວໂລກ: hooks ສໍາລັບການປິ່ນປົວ, ການປິ່ນປົວຄໍາຖາມ / ຄໍາຕອບ, ແລະອື່ນໆ ພວກເຮົາມີຄວາມຕ້ອງການທີ່ຈະຊອກຫາຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບການທົດສອບແລະການປິ່ນປົວຂອງລູກຄ້າຂອງທ່ານ. ມັນບໍ່ມີສິ່ງທີ່ສວຍງາມທີ່ທ່ານບໍ່ສາມາດສ້າງທ່ານເອງ, ແຕ່ມັນລວມເອົາທ່ານຈາກການຂຽນ, ການທົດສອບ, ແລະການປົກປັກຮັກສາທັງຫມົດທີ່ boilerplate. ມັນເປັນ wrapper ຄວາມປອດໄພທີ່ bakes ໃນຮູບແບບລະດັບຜະລິດຕະພັນ (ເຊັ່ນ circuit breaker ແລະ backoff) ດັ່ງນັ້ນທ່ານສາມາດ concentrated ກ່ຽວກັບ app ຂອງທ່ານ, ບໍ່ແມ່ນ logic ຂອງທ່ານ. ມັນຍັງ stops at the fetch layer, ດັ່ງນັ້ນທ່ານສາມາດນໍາໃຊ້ caching ຂອງທ່ານເອງ, ການຄຸ້ມຄອງສະຖານທີ່, ແລະ libraries UI ໃນຂະນະທີ່ທ່ານຕ້ອງການ. ffetch ພາສາລາວ ການນໍາສະເຫນີຕົ້ນຕໍຂອງບົດຄວາມນີ້ແມ່ນບໍ່ວ່າທ່ານຈະໃຊ້ ຂ້າພະເຈົ້າສືບຕໍ່ໄດ້ຮັບການປະທັບໃຈສໍາລັບລູກຄ້າຂອງພວກເຮົາ - ຂ້າພະເຈົ້າຫວັງວ່າຈະໄດ້ເຮັດວຽກຮ່ວມກັບທ່ານອີກເທື່ອຫນຶ່ງ! ffetch ສິ່ງທີ່ທ່ານຈໍາເປັນຕ້ອງເຮັດໄດ້ depende ຂອງກໍລະນີແລະຄວາມຕ້ອງການການນໍາໃຊ້ທີ່ພິເສດຂອງທ່ານ, ແຕ່ທ່ານບໍ່ສາມາດໄປຢ້ຽມຢາມການຜະລິດເພື່ອປິ່ນປົວເສັ້ນທາງທີ່ດີເລີດພຽງແຕ່. Things can and will go wrong, and your app needs to handle at least the most common failure scenarios. ແລະ ທ່ານສາມາດຊ່ວຍເຫຼືອກັບການນີ້. ffetch