Promise.all () แล้ว () แก้ไข?


96

การใช้ Node 4.x. เมื่อคุณมีPromise.all(promises).then()สิ่งที่เป็นวิธีการที่เหมาะสมในการแก้ไขข้อมูลและผ่านมันไปยัง.then()?

ฉันต้องการทำสิ่งนี้:

Promise.all(promises).then(function(data){
  // Do something with the data here
}).then(function(data){
  // Do more stuff here
});

แต่ฉันไม่แน่ใจว่าจะรับข้อมูลไปที่ 2 .then()ได้อย่างไร ฉันไม่สามารถใช้ในครั้งแรกresolve(...) .then()ฉันคิดว่าฉันสามารถทำได้:

return Promise.all(promises).then(function(data){
  // Do something with the data here
  return data;
}).then(function(data){
  // Do more stuff here
});

แต่ดูเหมือนจะไม่ใช่วิธีที่เหมาะสมที่จะทำ ... อะไรคือแนวทางที่ถูกต้องสำหรับสิ่งนี้?

คำตอบ:


143

แต่ดูเหมือนจะไม่ใช่วิธีที่เหมาะสม ..

นั่นเป็นวิธีที่เหมาะสมที่จะทำ (หรืออย่างน้อยก็เป็นวิธีที่เหมาะสมที่จะทำ) นี่คือลักษณะสำคัญของคำสัญญาเป็นท่อและข้อมูลสามารถถูกนวดโดยตัวจัดการต่างๆในท่อ

ตัวอย่าง:

const promises = [
  new Promise(resolve => setTimeout(resolve, 0, 1)),
  new Promise(resolve => setTimeout(resolve, 0, 2))
];
Promise.all(promises)
  .then(data => {
    console.log("First handler", data);
    return data.map(entry => entry * 10);
  })
  .then(data => {
    console.log("Second handler", data);
  });

( catchจัดการละเว้นสำหรับความกะทัดรัด. ในรหัสการผลิต, เสมอทั้งเผยแพร่สัญญาหรือการจัดการปฏิเสธ.)

ผลลัพธ์ที่เราเห็นคือ:

เครื่องจัดการคนแรก [1,2]
มือสอง [10,20]

... เนื่องจากตัวจัดการแรกได้รับความละเอียดของสัญญาทั้งสอง ( 1และ2) เป็นอาร์เรย์จากนั้นจึงสร้างอาร์เรย์ใหม่โดยแต่ละตัวคูณด้วย 10 แล้วส่งกลับ ตัวจัดการมือสองจะได้รับสิ่งที่ตัวจัดการแรกส่งคืน

หากงานเพิ่มเติมที่คุณทำอยู่เป็นแบบซิงโครนัสคุณสามารถวางไว้ในตัวจัดการแรกได้:

ตัวอย่าง:

const promises = [
  new Promise(resolve => setTimeout(resolve, 0, 1)),
  new Promise(resolve => setTimeout(resolve, 0, 2))
];
Promise.all(promises)
  .then(data => {
    console.log("Initial data", data);
    data = data.map(entry => entry * 10);
    console.log("Updated data", data);
    return data;
  });

... แต่ถ้าเป็นแบบอะซิงโครนัสคุณจะไม่ต้องการทำเช่นนั้นเมื่อมันถูกซ้อนกันและการทำรังจะหลุดมือไปอย่างรวดเร็ว


1
น่าสนใจ. ขอบคุณ. ดังนั้นจึงเป็นไปไม่ได้ที่จะrejectให้ค่าหลังจากPromiseฟังก์ชันเริ่มต้น? หรือจะโยนข้อผิดพลาดที่ใดก็ได้ในห่วงโซ่จะพาคุณไป.catch()? ถ้าเป็นเช่นนั้นจุดเริ่มต้นrejectคืออะไร? ทำไมไม่เพียงแค่โยนข้อผิดพลาด? ขอขอบคุณอีกครั้ง
Jake Wilson

6
@JakeWilson: เป็นคำถามที่แตกต่างกัน แต่คุณกำลังสับสนสองสิ่งที่แยกจากกัน: การสร้างและการกำหนดคำสัญญาและการจัดการคำสัญญา เมื่อคุณสร้างและปักหลักสัญญาที่คุณใช้และresolve rejectเมื่อคุณจัดการหากการประมวลผลของคุณล้มเหลวคุณจะมีข้อยกเว้นเพื่อทริกเกอร์เส้นทางความล้มเหลว และใช่คุณสามารถทิ้งข้อยกเว้นจากการPromiseโทรกลับเดิมได้(แทนที่จะใช้reject) แต่ความล้มเหลวทั้งหมดไม่ใช่ข้อยกเว้น
TJ Crowder

2

ของคุณreturn dataวิธีการที่ถูกต้องว่าเป็นตัวอย่างของสัญญาผูกมัด หากคุณคืนสัญญาจากการ.then()โทรกลับ JavaScript จะแก้ไขสัญญานั้นและส่งข้อมูลไปยังการthen()โทรกลับครั้งต่อไป

.catch()เพียงระมัดระวังและให้แน่ใจว่าคุณจัดการกับข้อผิดพลาดกับ ปฏิเสธทันทีที่หนึ่งของสัญญาในการปฏิเสธอาร์เรย์Promise.all()


1

วันนี้ NodeJS รองรับasync/awaitไวยากรณ์ใหม่ นี่เป็นไวยากรณ์ที่ง่ายและทำให้ชีวิตง่ายขึ้นมาก

async function process(promises) { // must be an async function
    let x = await Promise.all(promises);  // now x will be an array
    x = x.map( tmp => tmp * 10);              // proccessing the data.
}

const promises = [
   new Promise(resolve => setTimeout(resolve, 0, 1)),
   new Promise(resolve => setTimeout(resolve, 0, 2))
];

process(promises)

เรียนรู้เพิ่มเติม:


1
ฉันจะส่งผ่านพารามิเตอร์ไปยังแต่ละสัญญาจากกระบวนการได้อย่างไร @ Aminadav Glickshtein
bhaRATh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.