หากต้องการดูวิธีการที่ผิดพลาดให้พิมพ์ console.log ที่ส่วนท้ายของวิธีการ
สิ่งที่ผิดปกติ:
- คำสั่งโดยพลการ
- printFiles สามารถทำงานให้เสร็จก่อนที่จะพิมพ์ไฟล์
- ประสิทธิภาพต่ำ
สิ่งเหล่านี้ไม่ได้ผิดเสมอไป แต่บ่อยครั้งอยู่ในกรณีใช้งานมาตรฐาน
โดยทั่วไปแล้วการใช้ forEach จะส่งผลให้ทั้งหมดยกเว้นครั้งสุดท้าย มันจะเรียกแต่ละฟังก์ชั่นโดยไม่ต้องรอฟังก์ชั่นความหมายมันบอกให้ฟังก์ชั่นทั้งหมดที่จะเริ่มต้นแล้วเสร็จโดยไม่ต้องรอฟังก์ชั่นที่จะเสร็จสิ้น
import fs from 'fs-promise'
async function printFiles () {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'))
for(const file of files)
console.log(await file)
}
printFiles()
นี่คือตัวอย่างใน JS พื้นเมืองที่จะรักษาความสงบเรียบร้อยป้องกันไม่ให้ฟังก์ชันส่งคืนก่อนกำหนดและในทางทฤษฎีจะรักษาประสิทธิภาพที่ดีที่สุดไว้
นี่จะ:
- เริ่มต้นไฟล์ทั้งหมดที่อ่านว่าจะเกิดขึ้นในแบบคู่ขนาน
- เก็บรักษาคำสั่งซื้อโดยใช้แผนที่เพื่อแมปชื่อไฟล์ที่สัญญาว่าจะรอ
- รอแต่ละสัญญาตามลำดับที่กำหนดโดยอาร์เรย์
ด้วยวิธีนี้ไฟล์แรกจะถูกแสดงทันทีที่พร้อมใช้งานโดยไม่ต้องรอให้ไฟล์อื่นพร้อมใช้งานก่อน
มันจะโหลดไฟล์ทั้งหมดในเวลาเดียวกันแทนที่จะต้องรอให้ไฟล์แรกเสร็จก่อนจึงจะสามารถเริ่มอ่านไฟล์ที่สองได้
สิ่งเดียวที่ดึงกลับมาได้คือเวอร์ชันดั้งเดิมคือถ้าหากมีการอ่านหลายครั้งพร้อมกันก็ยากที่จะจัดการกับข้อผิดพลาดเนื่องจากมีข้อผิดพลาดเกิดขึ้นในแต่ละครั้ง
ด้วยเวอร์ชันที่อ่านไฟล์ในแต่ละครั้งจากนั้นจะหยุดในความล้มเหลวโดยไม่ต้องเสียเวลาพยายามอ่านไฟล์เพิ่มเติม แม้ว่าจะมีระบบการยกเลิกที่ซับซ้อนมันก็ยากที่จะหลีกเลี่ยงความล้มเหลวในไฟล์แรก แต่การอ่านไฟล์อื่น ๆ ส่วนใหญ่เช่นกัน
ประสิทธิภาพไม่สามารถคาดการณ์ได้เสมอ ในขณะที่หลาย ๆ ระบบจะทำงานได้เร็วขึ้นด้วยการอ่านไฟล์แบบขนานบางระบบอาจชอบการเรียงตามลำดับ บางตัวเป็นแบบไดนามิกและอาจเปลี่ยนไปตามโหลดการเพิ่มประสิทธิภาพที่เสนอความหน่วงไม่ได้ให้ปริมาณงานที่ดีภายใต้การแข่งขันที่หนักหน่วง
นอกจากนี้ยังไม่มีการจัดการข้อผิดพลาดในตัวอย่างนั้น หากมีบางสิ่งที่ต้องการให้ทุกคนแสดงได้สำเร็จหรือไม่แสดงเลยจะไม่ทำเช่นนั้น
ในการทดลองเชิงลึกขอแนะนำให้ใช้ console.log ในแต่ละขั้นตอนและแก้ไขปัญหาการอ่านไฟล์ปลอม (ล่าช้าแบบสุ่มแทน) แม้ว่าการแก้ปัญหาจำนวนมากดูเหมือนจะทำเช่นเดียวกันในกรณีที่เรียบง่าย แต่ทุกคนมีความแตกต่างเล็กน้อยที่ใช้เวลาพิจารณาบางอย่างพิเศษเพื่อบีบออก
ใช้จำลองนี้เพื่อช่วยบอกความแตกต่างระหว่างวิธีแก้ไขปัญหา:
(async () => {
const start = +new Date();
const mock = () => {
return {
fs: {readFile: file => new Promise((resolve, reject) => {
// Instead of this just make three files and try each timing arrangement.
// IE, all same, [100, 200, 300], [300, 200, 100], [100, 300, 200], etc.
const time = Math.round(100 + Math.random() * 4900);
console.log(`Read of ${file} started at ${new Date() - start} and will take ${time}ms.`)
setTimeout(() => {
// Bonus material here if random reject instead.
console.log(`Read of ${file} finished, resolving promise at ${new Date() - start}.`);
resolve(file);
}, time);
})},
console: {log: file => console.log(`Console Log of ${file} finished at ${new Date() - start}.`)},
getFilePaths: () => ['A', 'B', 'C', 'D', 'E']
};
};
const printFiles = (({fs, console, getFilePaths}) => {
return async function() {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'));
for(const file of files)
console.log(await file);
};
})(mock());
console.log(`Running at ${new Date() - start}`);
await printFiles();
console.log(`Finished running at ${new Date() - start}`);
})();
for ... of ...
ทำงาน