Hi,
ฉันสัญญาว่าคุณจะได้รับบทสรุปของโพสต์นี้ในตอนท้าย
การดำเนินการแบบอะซิงโครนัสถือเป็นหัวใจสำคัญของการนำการโต้ตอบไปใช้ในแอปพลิเคชัน JavaScript สมัยใหม่ สิ่งเหล่านี้จะใช้เมื่อทำการเรียก API, คำขอเครือข่าย หรือแม้แต่ผ่านฟังก์ชันการหน่วงเวลาพื้นฐาน
การดำเนินการแบบอะซิงโครนัสใช้สัญญา ฟังก์ชันการโทรกลับ หรือ async/await โดยทั่วไป การดำเนินการเหล่านี้เป็นเอกพจน์และไม่จำเป็นต้องรวมการดำเนินการอะซิงก์หลายรายการไว้ในที่เดียว
เมื่อเร็วๆ นี้ ฉันเริ่มทำงานเพื่อสร้างบริการรวบรวมที่ใช้ API ของบุคคลที่สามหลายรายการและรวบรวมข้อมูลผลลัพธ์ ในโพสต์นี้ เราจะเรียนรู้วิธีสร้างคำขอ async พร้อมกันโดยใช้ Promise.all()
ใน JavaScript นอกจากนี้ เราจะได้เรียนรู้วิธีจำกัดคำขอเหล่านี้ให้ทำงานในบางกลุ่ม/บางส่วนในแต่ละครั้ง
ใช้ Promise.all()
ฟังก์ชันอะซิงก์เพื่อดึงข้อมูลจาก API โดยทั่วไปจะมีลักษณะดังนี้:
async function fetchData() {
const res = await axios.get("./names.json");
console.log(res.data);
}
ที่นี่เราใช้ Axios ซึ่งเป็นไคลเอนต์ HTTP ตามสัญญา เพื่อสร้างคำขอ HTTP เพื่อดึงข้อมูลในไฟล์ json ในเครื่อง อีกทางเลือกหนึ่งนอกเหนือจากการใช้ async/await คือการใช้เมธอด .then()
ของสัญญา
ด้วย Promise.all()
เราจัดการคำขอที่คล้ายกันหลายรายการพร้อมกัน และส่งคืนการตอบกลับแบบรวมเพียงรายการเดียว Promise.all() รับคำสัญญาที่สามารถทำซ้ำได้ (อาร์เรย์) โดยจะส่งคืนอาร์เรย์ที่มีการแก้ไขสัญญาแต่ละรายการในลำดับเดียวกัน
หากสัญญาใดๆ ใน Promise.all() ถูกปฏิเสธ การรวมสัญญาจะถูกปฏิเสธ นี่คือตัวอย่างด้านล่าง:
const fetchNames = async () => {
try {
const res = await Promise.all([
axios.get("./names.json"),
axios.get("./names-mid.json"),
axios.get("./names-old.json")
]);
const data = res.map((res) => res.data);
console.log(data.flat());
} catch {
throw Error("Promise failed");
}
};
ตัวอย่างโค้ดนี้ซับซ้อนกว่าและอยู่ในบล็อก try/catch เพื่อตรวจจับความล้มเหลวในการแก้ไขสัญญา
Promise.all() ไม่ได้แก้ไขสัญญาและรวมเฉพาะสัญญาไว้ในอาร์เรย์ที่มีความละเอียดเดียวเท่านั้น ฉันจะตัดเรื่องไร้สาระออก ซึ่งหมายความว่าคุณต้องใช้ Promise.all() กับ
await
หรือ.then()
เพื่อแก้ไข 😁
.flat()
เป็นวิธีอาร์เรย์ที่มีประโยชน์ซึ่งจะทำให้อาร์เรย์เรียบขึ้น ก่อนหน้านี้จะทำได้ด้วยฟังก์ชัน forloop หรือลด
อีกทางเลือกหนึ่งที่มี fetch
API มีลักษณะดังนี้:
const fetchNames = async () => {
try {
const res = await Promise.all([
fetch("./names.json"),
fetch("./names-mid.json"),
fetch("./names-old.json")
]);
const data = await Promise.all(res.map(r => r.json()))
console.log(data.flat());
} catch {
throw Error("Promise failed");
}
};
หลังจากใช้ fetch()
แล้ว .json()
จะต้องแยกวิเคราะห์การตอบสนอง และยังคืนสัญญาอีกด้วย! สัญญาไว้หลายข้อ นี่กำลังกลายเป็นเทเลโนเวลาแล้ว!
จำเป็นต้องมีสัญญาอื่นทั้งหมดเพื่อรวบรวมคำตอบ
เพื่อให้เข้าใจผลกระทบของ Promise.all
ได้ดีขึ้น เราจะสร้างฟังก์ชันจับเวลาที่แก้ไขสัญญาหลังจากช่วงระยะเวลาหนึ่ง
การสังเกตด้วยฟังก์ชันจับเวลา
เราจะสร้างคำสัญญาสามประการด้วย:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
const newValue = Math.floor(Math.random() * 20);
resolve(newValue);
}, 5000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
const newValue = Math.floor(Math.random() * 20);
resolve(newValue);
}, 8000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
const newValue = Math.floor(Math.random() * 20);
resolve(newValue);
}, 2000);
});
แต่ละคำสัญญาจะได้รับการแก้ไขในเวลาที่ต่างกัน 5, 8 และ 2 วินาทีตามลำดับ
การเรียกแต่ละฟังก์ชันแยกกันใน async/await จะส่งกลับค่าที่ได้รับการแก้ไขของแต่ละฟังก์ชันหลังจากระยะเวลาที่กำหนด การรวมผลลัพธ์จะต้องมีการดำเนินการ JavaScript เพิ่มเติมเพื่อสร้างอาร์เรย์
การโทรทั้งหมดใน Promise.all()
จะเป็นการแก้ปัญหาทั้งหมดพร้อมกัน ในกรณีนี้ เวลาที่ฟังก์ชันต้องใช้เวลาดำเนินการมากที่สุดคือ 8 วินาที
เมื่อใช้ Promise.all()
เรามี:
const fetchAsyncData = async () => {
const res = await Promise.all([promise1, promise2, promise3]);
console.log(res);
};
มันเป็นโค้ดที่มีประสิทธิภาพและสะอาดกว่าสำหรับฉัน 😃
การจำกัดการเกิดพร้อมกัน
อย่างไรก็ตาม ในเรื่องประสิทธิภาพ คุณอาจต้องการส่งคำขอจำนวนมากพร้อมกัน แทนที่จะทำทั้งหมดในคราวเดียว มันจะเป็นการดีกว่าถ้าจะแบ่งเป็นชิ้นๆ
แพ็คเกจ npm ที่มีประโยชน์ที่ฉันพบว่าทำคือ "p-limit"
คุณสามารถเพิ่มลงในโครงการของคุณโดยใช้ npm หรือเส้นด้ายด้วย:
npm install p-limit
yarn add p-limit
สร้างขีดจำกัดและระบุการนับพร้อมกันด้วย:
import pLimit from 'p-limit'
const limit = pLimit(2)
ใช้ขีดจำกัดนี้ในสัญญากับ:
const res = await Promise.all([
limit(() => promise1),
limit(() => promise2),
limit(() => promise3)
]);
บล็อกนี้รันสองสัญญาในแต่ละครั้ง
นี่คือ "ลิงก์ CodeSandbox ที่มีบล็อกโค้ดทั้งหมดที่ทำงานในแอป React และบันทึกข้อมูลไปยังคอนโซล"
สรุป
เช่นเดียวกับคำสัญญาใน JavaScript คุณรู้ว่าบทสรุปนี้กำลังจะมาถึง ฉันบอกคุณตั้งแต่ต้นแล้ว นี่เป็นเหมือนสัญญาใน JavaScript ในโพสต์นี้ เราได้ดูวิธีการแก้ไขสัญญาแบบรวมโดยใช้ Promise.all()
และจำกัดการทำงานพร้อมกันตามที่จำเป็นโดยใช้ p-limit
วิธีการตรวจสอบสัญญาอื่น ๆ ได้แก่ :
นี่คือการพัฒนาให้ดีขึ้น 🥂
วิลเลียม
บทความนี้เผยแพร่ครั้งแรกใน Hackmamba