Promise.resolve vs New Promise (แก้ไข)


98

ฉันใช้ bluebird และฉันเห็นสองวิธีในการแก้ไขฟังก์ชันซิงโครนัสให้เป็น Promise แต่ฉันไม่เข้าใจความแตกต่างระหว่างทั้งสองวิธี ดูเหมือนว่า stacktrace จะแตกต่างกันเล็กน้อยดังนั้นจึงไม่ใช่แค่ an aliasใช่ไหม?

แล้ววิธีที่ต้องการคืออะไร?

ทางก

function someFunction(someObject) {
  return new Promise(function(resolve) {
    someObject.resolved = true;
    resolve(someObject);
  });
}

ทาง B

function someFunction(someObject) {
  someObject.resolved = true;
  return Promise.resolve(someObject);
}

3
Promise.resolveเป็นเพียงน้ำตาล
Qantas 94 Heavy

1
คำตอบสั้น ๆ - ไม่มีความแตกต่างในการใช้งาน เพียงแค่น้ำตาล
Pinal

@Pinal "น้ำตาล" คืออะไร?
doubleOrt

6
@ ราศีพฤษภ. Syntactic sugarเป็นไวยากรณ์ที่ออกแบบมาเพื่อให้อ่านหรือแสดงออกได้ง่ายขึ้น โปรดดูที่: วิกิพีเดีย
Wyck

คำตอบ:


85

ตรงกันข้ามกับคำตอบทั้งสองในความคิดเห็น - มีความแตกต่าง

ในขณะที่

Promise.resolve(x);

โดยพื้นฐานแล้วจะเหมือนกับ

new Promise(function(r){ r(x); });

มีความละเอียดอ่อน

โดยทั่วไปฟังก์ชันการส่งคืนสัญญาควรมีการรับประกันว่าไม่ควรโยนพร้อมกันเนื่องจากอาจโยนแบบอะซิงโครนัส เพื่อป้องกันผลลัพธ์ที่ไม่คาดคิดและสภาพการแข่งขัน - โดยปกติการขว้างจะถูกแปลงเป็นการปฏิเสธที่ส่งคืน

เมื่อคำนึงถึงสิ่งนี้ - เมื่อสร้างข้อมูลจำเพาะตัวสร้างสัญญาจะปลอดภัย

เกิดอะไรขึ้นถ้าsomeObjectเป็นundefined?

  • ทาง A ส่งคืนคำสัญญาที่ถูกปฏิเสธ
  • ทาง B พ่นพร้อมกัน

Bluebird เห็นสิ่งนี้และ Petka ได้เพิ่มPromise.methodเพื่อแก้ไขปัญหานี้เพื่อให้คุณสามารถใช้ค่าส่งคืนได้ต่อไป ดังนั้นวิธีที่ถูกต้องและง่ายที่สุดในการเขียนสิ่งนี้ใน Bluebird นั้นไม่ได้เป็นเช่นนั้น - มันคือ:

var someFunction = Promise.method(function someFunction(someObject){
    someObject.resolved = true;
    return someObject;
});

Promise.method จะแปลงการโยนเป็นการปฏิเสธและส่งกลับไปแก้ไขให้คุณ เป็นวิธีที่ปลอดภัยที่สุดในการทำเช่นนี้และสามารถดูดซึมthenผ่านค่าที่ส่งคืนได้ดังนั้นจึงสามารถทำงานได้แม้ว่าsomeObjectจะเป็นคำสัญญาก็ตาม

โดยทั่วไปPromise.resolveใช้สำหรับการหล่อวัตถุและคำสัญญาต่างประเทศ (thenables) เพื่อสัญญา นั่นคือกรณีการใช้งาน


"โดยทั่วไปฟังก์ชันการคืนสัญญาควรมีการรับประกันว่าไม่ควรโยนพร้อมกันเนื่องจากอาจโยนแบบอะซิงโครนัส" คุณช่วยขยายความได้ไหมว่าเหตุใดฟังก์ชันจึงควรเป็นแบบซิงโครนัสหรืออะซิงโครนัส แต่ไม่ใช่ทั้งสองอย่าง ตอนนี้ฉันสนุกกับ Promise.resolve () คุณจะบอกว่าการใช้Promise.resolve()เป็นรูปแบบการต่อต้านหรือไม่?
Ashley Coolman

2
@AshleyCoolman ดูblog.izs.me/post/59142742143/designing-apis-for-asynchrony - วิธีการที่บางครั้งมีลักษณะการทำงานแบบไม่พร้อมควรเสมอทำเช่นนั้นเพื่อความมั่นคง
Benjamin Gruenbaum

ไม่Promise.resolve()สร้างตัวอย่างใหม่ของPromiseในลักษณะเดียวกับการใช้new? ถ้าไม่return Promise.resolve(yourCode)จะเร็วกว่าและหลีกเลี่ยงการพ่นซิงโครนัส
Steven Vachon

1
ฉันรู้สึกไม่ดีฉันใช้ "Promise.resolve () แล้ว (ฟังก์ชัน () {/ * กรณีที่สามารถส่งข้อผิดพลาด * /}) จากนั้น ... " เพื่อให้แน่ใจว่าข้อผิดพลาดกลายเป็นคำสัญญาที่ถูกปฏิเสธ ... ฉันจะดูเพิ่มเติมใน "Promise.method"
Polopollo

1
@Polopollo หรือPromise.coroutineซึ่งมีประโยชน์มากยิ่งขึ้น
Benjamin Gruenbaum

18

มีความแตกต่างอีกประการหนึ่งที่ไม่ได้กล่าวถึงในคำตอบหรือความคิดเห็นข้างต้น:

ถ้าsomeObjectเป็นPromise, new Promise(resolve)จะเสียค่าใช้จ่ายสองเห็บเพิ่มเติม


เปรียบเทียบข้อมูลโค้ดสองรายการต่อไปนี้:

const p = new Promise(resovle => setTimeout(resovle));

new Promise(resolve => resolve(p)).then(() => {
  console.log("tick 3");
});

p.then(() => {
  console.log("tick 1");
}).then(() => {
  console.log("tick 2");
});

const p = new Promise(resovle => setTimeout(resovle));

Promise.resolve(p).then(() => {
  console.log("tick 3");
});

p.then(() => {
  console.log("tick 1");
}).then(() => {
  console.log("tick 2");
});

ตัวอย่างข้อมูลที่สองจะพิมพ์ 'ติ๊ก 3' ก่อน ทำไม?

  • หากค่าเป็นสัญญาPromise.resolve(value)จะส่งคืนค่าทุกประการ Promise.resolve(value) === valueจะเป็นจริง ดูMDN

  • แต่new Promise(resolve => resolve(value))จะคืนคำสัญญาใหม่ที่ล็อคไว้เพื่อทำตามvalueสัญญา จำเป็นต้องมีการทำเครื่องหมายเพิ่มอีกหนึ่งครั้งเพื่อทำการ 'ล็อคอิน'

    // something like:
    addToMicroTaskQueue(() => {
      p.then(() => {
        /* resolve newly promise */
      })
        // all subsequent .then on newly promise go on from here
        .then(() => {
          console.log("tick 3");
        });
    });
    

    การtick 1 .thenโทรจะทำงานก่อน


อ้างอิง:

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