อะไรคือความแตกต่างระหว่างมูลค่าส่งคืนหรือสัญญาแก้ไขจากนั้น ()


314

อะไรคือความแตกต่างระหว่าง:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return "bbb";
  })
  .then(function(result) {
    console.log(result);
  });

และนี่:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return Promise.resolve("bbb");
  })
  .then(function(result) {
    console.log(result);
  });

ฉันกำลังถามว่าฉันได้รับพฤติกรรมที่แตกต่างโดยใช้บริการ Angular และ $ http ด้วยการผูกมัด. แล้ว () รหัสน้อยเกินไปดังนั้นก่อนตัวอย่างข้างต้น


1
คุณเห็น "พฤติกรรมที่แตกต่าง" อะไร ตัวอย่างทั้งสองควรใช้งานได้และมีพฤติกรรมใกล้เคียงกัน Promise.resolve()ในตัวอย่างที่สองไม่จำเป็น
JLRishe

4
@pixelbits ไม่มีอะไรผิดพลาดใด ๆ กับการส่งคืนสัญญาจากthenผู้จัดการในความเป็นจริงมันเป็นลักษณะสำคัญของสเป็คสัญญาที่คุณสามารถทำได้

โปรดทราบว่าการทำงานนี้กับซ้อนกันโดยพลthens - คำว่า 'ภาษาอื่น ๆ' สำหรับเรื่องนี้ก็คือว่าthenเป็นทั้งและmap flatMap
Benjamin Gruenbaum

1
ในบรรทัดที่ 2 ทำไมคุณต้องโทรหา res ("aaa") ทำไมไม่สามารถส่งคืน "aaa" ได้อย่างเพียงพอและ Promise catch เพื่อแก้ไข () ในลักษณะเดียวกับที่มันจับข้อยกเว้นสำหรับการปฏิเสธ ()
Sam Liddicott

1
@ SamLiddicott มีคำถามเดียวกันในขณะที่เหมืองจะค่อนข้างซับซ้อน: new Promise((res, rej) => { return fetch('//google.com').then(() => { return "haha"; }) }).then((result) => alert(result));รหัสนี้จะหยุดทำงาน (ไม่สามารถแก้ไขได้ตลอดไป) แต่ถ้าฉันเปลี่ยนreturn "haha";เป็นreturn res("haha");แล้วมันจะทำงานและแจ้งเตือน "haha" การดึงข้อมูล () ไม่จากนั้น () ห่อ "ฮ่าฮ่า" ไว้ในสัญญาที่ได้รับการแก้ไขแล้วหรือไม่
Shaung Cheng

คำตอบ:


138

กฎคือถ้าฟังก์ชันที่อยู่ในthenตัวจัดการส่งคืนค่าสัญญาจะแก้ไข / ปฏิเสธด้วยค่านั้นและถ้าฟังก์ชันส่งคืนสัญญาสิ่งที่เกิดขึ้นคือthenประโยคถัดไปจะเป็นthenส่วนของสัญญาที่ฟังก์ชันส่งคืนดังนั้นในกรณีนี้ตัวอย่างแรกที่ตกอยู่ในลำดับปกติของthensและพิมพ์ค่าตามที่เราคาดไว้ในตัวอย่างที่สองวัตถุสัญญาที่ได้รับคืนเมื่อคุณทำPromise.resolve("bbb")เช่นนั้นคือสิ่งthenที่ถูกเรียกเมื่อถูกผูกมัด (สำหรับเจตนาและวัตถุประสงค์ทั้งหมด) วิธีการใช้งานได้อธิบายไว้ด้านล่างโดยละเอียดยิ่งขึ้น

การอ้างอิงจากข้อกำหนดของสัญญา / A +:

ขั้นตอนความละเอียดสัญญาเป็นงานนามธรรมการเป็น input [[Resolve]](promise, x)สัญญาและค่าที่เราแสดงเป็น ถ้าxเป็น thenable จะพยายามที่จะทำให้สัญญานำของรัฐxภายใต้สมมติฐานที่ว่า x พฤติกรรมอย่างน้อยบ้างเช่นสัญญา xมิฉะนั้นจะตอบสนองสัญญาด้วยค่า

การรักษาแบบใช้แล้วนั้นจะช่วยให้การใช้งานสัญญาในการทำงานร่วมกันตราบเท่าที่พวกเขาเปิดเผยวิธีการสัญญา / A + - ที่สอดคล้องกันแล้ว นอกจากนี้ยังอนุญาตให้การใช้งานสัญญา / A + สามารถใช้งาน“ ดูดซับ” การดำเนินการที่ไม่เป็นไปตามข้อกำหนดด้วยวิธีการที่สมเหตุสมผลแล้ว

สิ่งสำคัญที่ควรสังเกตที่นี่คือบรรทัดนี้:

ถ้าxเป็นสัญญาให้ใช้สถานะ [3.4]

ลิงก์: https://promisesaplus.com/#point-49


4
"ใช้สถานะของมัน" เป็นวิธีที่รัดกุมและมีประโยชน์ในการแสดงพฤติกรรมเมื่อthenตัวจัดการส่งคืนสัญญา +1 สำหรับการอ้างอิงข้อมูลจำเพาะ

69
ที่จริง - ส่วนที่เกี่ยวข้องของข้อมูลจำเพาะที่นี่คือความจริงที่[[Resolve]]เรียกว่าทั้งบนthenables และค่าดังนั้นโดยพื้นฐานแล้วมันจะตัดค่าด้วยสัญญาดังนั้นจึงreturn "aaa"เป็นเช่นเดียวกับreturn Promise.resolve("aaa")และreturn Promise.resolve("aaa")เป็นเช่นเดียวกับreturn Promise.resolve(Promise.resolve("aaa"))- เนื่องจากการแก้ไขคือ idempotent เรียกมันว่าค่า มากกว่าหนึ่งครั้งมีผลลัพธ์เหมือนกัน
Benjamin Gruenbaum

8
@Benjamin Gruenbaum หมายความว่าคืนนั้น"aaa"และreturn Promise.resolve("aaa")สามารถแลกเปลี่ยนได้ในthenables ในกรณีใด ๆ ?
CSnerd

9
ใช่นั่นคือสิ่งที่มันหมายถึง
Benjamin Gruenbaum

118

ในแง่ง่ายภายในthenฟังก์ชั่นการจัดการ:

A) เมื่อxใดคือค่า (ตัวเลข, สตริง, ฯลฯ ):

  1. return x เทียบเท่ากับ return Promise.resolve(x)
  2. throw x เทียบเท่ากับ return Promise.reject(x)

B) เมื่อxใดคือสัญญาที่มีการชำระบัญชีแล้ว (ไม่รอดำเนินการอีกต่อไป):

  1. return xเทียบเท่ากับreturn Promise.resolve(x)หากสัญญาได้รับการแก้ไขแล้ว
  2. return xเทียบเท่ากับreturn Promise.reject(x)หากสัญญาถูกปฏิเสธไปแล้ว

C) เมื่อxใดคือสัญญาที่ค้างอยู่:

  1. return xthenจะกลับมารอสัญญาและจะได้รับการประเมินในภายหลัง

อ่านเพิ่มเติมเกี่ยวกับหัวข้อนี้ในPromise.prototype.then () เอกสาร


93

ตัวอย่างของคุณทั้งคู่ควรมีพฤติกรรมเหมือนกัน

ค่าส่งกลับภายในจัดการจะกลายเป็นค่าความละเอียดของสัญญาที่กลับมาจากการที่then() then()หากมูลค่าที่ส่งคืนภายใน.then สัญญาคือสัญญาที่ส่งคืนโดยthen()จะ "รับสถานะ" ของสัญญานั้นและแก้ไข / ปฏิเสธเช่นเดียวกับสัญญาที่ส่งคืน

ในตัวอย่างแรกของคุณคุณกลับมา"bbb"ในthen()ตัวจัดการแรกดังนั้นจึง"bbb"ส่งผ่านไปยังถัดไปthen()ตัวจัดการ

ในตัวอย่างที่สองของคุณคุณส่งคืนสัญญาที่ได้รับการแก้ไขในทันทีพร้อมกับมูลค่า"bbb"ดังนั้นจึง"bbb"ส่งผ่านไปยังthen()ตัวจัดการถัดไป (ในPromise.resolve()นี่คือภายนอก)

ผลลัพธ์จะเหมือนกัน

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


1
คำตอบที่ดี! แล้วPromise.resolve();vs return;ล่ะ
FabianTe

2
@FabianTe เหล่านั้นยังจะมีผลเช่นเดียวกันยกเว้นแทนundefined "bbb"
JLRishe

51

คุณได้รับคำตอบที่เป็นทางการอยู่แล้ว ฉันคิดว่าฉันควรจะเพิ่มสั้น ๆ

สิ่งต่อไปนี้เหมือนกันกับสัญญา / A +สัญญา:

  • การโทรPromise.resolve(ในกรณีของคุณเป็นเหลี่ยม$q.when)
  • เรียกตัวสร้างสัญญาและการแก้ไขในตัวแก้ไขของมัน new $qในกรณีของคุณที่
  • คืนค่าจากการthenเรียกกลับ
  • การเรียก Promise.all บนอาร์เรย์ที่มีค่าจากนั้นแยกค่านั้น

ดังนั้นสิ่งต่อไปนี้เหมือนกันทั้งหมดสำหรับสัญญาหรือค่าธรรมดา X:

Promise.resolve(x);
new Promise(function(resolve, reject){ resolve(x); });
Promise.resolve().then(function(){ return x; });
Promise.all([x]).then(function(arr){ return arr[0]; });

และไม่แปลกใจเลยว่าข้อกำหนดของสัญญาขึ้นอยู่กับขั้นตอนการแก้ไขสัญญาซึ่งช่วยให้การทำงานร่วมกันระหว่างห้องสมุดง่ายขึ้น (เช่น $ q และสัญญาดั้งเดิม) และทำให้ชีวิตของคุณโดยรวมง่ายขึ้น เมื่อใดก็ตามที่การแก้ปัญหาที่สัญญาอาจเกิดขึ้นการแก้ไขเกิดขึ้นสร้างความสอดคล้องโดยรวม


ขอให้ฉันทำสิ่งที่เป็นจุดในการทำPromise.resolve().then(function(){ return x; });? ฉันพบ snipped ทำสิ่งที่คล้ายกัน (มันเรียกว่าฟังก์ชั่นภายในthenบล็อก) ฉันคิดว่ามันมากหรือน้อยเหมือนการหมดเวลา แต่มันเร็วขึ้นเล็กน้อย jsben.ch/HIfDo
Sampgun

ไม่มีประเด็นเหมือนกันกับ Promise.resolve (x) ในกรณี 99.99% (0.001% คือเราอยู่ในwithบล็อกเหนือวัตถุหรือพร็อกซีที่มีxaccess access ที่ส่งข้อยกเว้นในกรณีนั้น Promise.resolve (x) จะทำให้เกิดข้อผิดพลาด แต่Promise.resolve().then(function(){ return x; });จะเป็นสัญญาที่ถูกปฏิเสธเนื่องจากข้อผิดพลาดถูกส่งออกไป ในthen)
Benjamin Gruenbaum

คุณเชื่อมโยงสายฟ้าแลบที่ว่างเปล่าหรือไม่ได้บันทึก อย่างไรก็ตามฉันไม่ได้พูดถึงความแตกต่างระหว่างงบ ฉันกำลังพูดอย่างแม่นยำเกี่ยวกับสิ่งที่ฉันเขียน if (validator) { Promise.resolve().then(() => { this._cdRef.markForCheck(); }); }เพียงเพื่อจะชัดเจนมากขึ้นนี้คือข้อมูลที่ผมได้พูดคุยเกี่ยวกับ: นี่คือสัญญาที่ไม่ได้รับมอบหมายดังนั้นประเด็นคืออะไร? หมดเวลาจะมี (มากหรือน้อย) ผลเหมือนกันหรือไม่?
Sampgun

1
มันทำการโทรแบบอะซิงโครนัสหลังจากรหัสซิงโครนัสทั้งหมดเกิดขึ้น แต่ก่อนที่จะมี I / O ใด ๆ เกิดขึ้น ที่เรียกว่า "ความหมาย microtick"
Benjamin Gruenbaum

1

return Promise.resolve("bbb")แต่ที่แตกต่างก็คือว่าคุณกำลังสร้างสัญญาที่ไม่จำเป็นเมื่อคุณทำ กลับสัญญาจากonFulfilled()เตะปิดตัวจัดการความละเอียดสัญญา นั่นเป็นวิธีที่สัญญาผูกมัดทำงาน

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