การปฏิเสธสัญญาที่ไม่สามารถจัดการได้คืออะไร?


204

สำหรับการเรียนรู้ Angular 2 ฉันพยายามสอน

ฉันได้รับข้อผิดพลาดเช่นนี้:

(node:4796) UnhandledPromiseRejectionWarning: Unhandled promise rejection (r                                                                                                     ejection id: 1): Error: spawn cmd ENOENT
[1] (node:4796) DeprecationWarning: Unhandled promise rejections are deprecated.
In the future, promise rejections that are not handled will terminate the Node.
js process with a non-zero exit code.

ฉันผ่านคำถามและคำตอบต่าง ๆ ใน SO แต่ไม่สามารถค้นหาได้ว่า "การปฏิเสธคำสัญญาที่ไม่ได้จัดการ" คืออะไร

ทุกคนสามารถอธิบายให้ฉันฟังว่ามันคืออะไรError: spawn cmd ENOENTและเมื่อมันเกิดขึ้นและสิ่งที่ฉันต้องตรวจสอบเพื่อกำจัดคำเตือนนี้?


2
ฉันพลาดคำถามนี้! ฉันขอโทษสำหรับคำเตือนนี้ที่ทำให้เกิดความสับสน - เราปรับปรุงมันเป็น Node.js ที่ใหม่กว่าและเราจะทำให้ทุกอย่างดีขึ้นในไม่ช้า!
Benjamin Gruenbaum

สำเนาที่เป็นไปได้ของ: stackoverflow.com/questions/38265963/…
Christophe Roussy

@BenjaminGruenbaum มันได้รับการแก้ไขแล้วหรือยัง ฉันได้รับข้อผิดพลาดเดียวกันในโหนด v12.16.1
เด็ก desta

1
@Babydesta ดีเราแสดงข้อผิดพลาดที่ดีขึ้นในขณะนี้ด้วยการติดตามสแต็ก แต่เรายังคงไม่ผิดพลาดโหนดในการปฏิเสธการจัดการ เราอาจต้องเปิด PR เพื่อทำเช่นนั้น
Benjamin Gruenbaum

คำตอบ:


200

ที่มาของข้อผิดพลาดนี้อยู่ในความจริงที่ว่าแต่ละคนและทุกสัญญาที่คาดว่าจะจัดการกับการปฏิเสธสัญญาเช่นมี.catch ( ... ) คุณสามารถหลีกเลี่ยงสิ่งเดียวกันได้โดยการเพิ่ม. catch (... )ให้กับสัญญาในรหัสตามที่ระบุด้านล่าง

ตัวอย่างเช่นฟังก์ชั่น PTest () จะแก้ไขหรือปฏิเสธสัญญาตามมูลค่าของตัวแปรทั่วโลกsomevar

var somevar = false;
var PTest = function () {
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
            reject();
    });
}
var myfunc = PTest();
myfunc.then(function () {
     console.log("Promise Resolved");
}).catch(function () {
     console.log("Promise Rejected");
});

ในบางกรณีข้อความ"การปฏิเสธสัญญาที่ไม่สามารถจัดการได้"จะเกิดขึ้นแม้ว่าเราจะมี. catch (.. ) เขียนขึ้นสำหรับสัญญา ทุกอย่างเกี่ยวกับวิธีที่คุณเขียนรหัสของคุณ รหัสต่อไปนี้จะสร้าง"การปฏิเสธสัญญาที่ไม่สามารถจัดการได้"แม้ว่าเราจะจัดการอยู่catchก็ตาม

var somevar = false;
var PTest = function () {
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
            reject();
    });
}
var myfunc = PTest();
myfunc.then(function () {
     console.log("Promise Resolved");
});
// See the Difference here
myfunc.catch(function () {
     console.log("Promise Rejected");
});

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


4
ดูเหมือนว่าจะทำงานถ้าคุณเพิ่มmyFunc = myFunct.then...ในตัวอย่างที่สอง
einstein

@ einstein ดูเหมือนว่าจะทำงานได้เพราะคุณกำลังสร้างสายโซ่เดียวกันกับในตัวอย่างแรก:var x = foo(); x = x.then(...); x = x.catch(...)
randomsock

4
@einstein ในตัวอย่างเชนด์ของคุณเมื่อคุณพูดว่า "ด้วยเหตุผลบางอย่าง Java Script ถือว่าเครื่องยนต์เป็นสัญญาโดยไม่ต้องยกเลิกสัญญาการจัดการปฏิเสธ" ไม่ได้เป็นแบบนี้เพราะและข้อยกเว้นจะถูกโยนใน.then(() => {...})ที่ที่คุณจะไม่ได้รับการจัดการ? ฉันไม่คิดว่าจะทำเช่นเดียวกับที่คุณโยงพวกเขา ใช่ไหม?
Simon Legg

8
@DKG เกี่ยวกับจุดที่สองของคุณเป็นน้ำตาลไวยากรณ์สำหรับcatch then(undefined, onRejected)ตั้งแต่ที่คุณโทรไปแล้วใน myfunc และทำให้เกิดข้อผิดพลาดก็จะไม่โทรไป (ไม่ได้กำหนดบนถูกปฏิเสธ) ในสัญญาเดิมอีกครั้ง
เควินลี

1
จะเปลี่ยนที่ไหน ฉันใช้อิออน 3 เมื่อฉันกดอิออนคอร์โดวาบิลด์ andorid ให้ฉันข้อผิดพลาดนี้
Sagar Kodte

35

นี่คือเมื่อ a Promiseเสร็จสมบูรณ์ด้วย.reject()หรือมีข้อยกเว้นถูกโยนในasyncรหัสดำเนินการและไม่มีการ.catch()จัดการปฏิเสธ

คำมั่นสัญญาที่ถูกปฏิเสธนั้นเป็นเหมือนข้อยกเว้นที่ทำให้เข้าสู่จุดเข้าใช้งานของแอปพลิเคชันและทำให้เกิดข้อผิดพลาดของรูทจัดการ

ดูสิ่งนี้ด้วย


จะเปลี่ยนที่ไหน ฉันใช้อิออน 3 เมื่อฉันกดอิออนคอร์โดวาบิลด์ andorid ให้ฉันข้อผิดพลาดนี้
Sagar Kodte

ยากที่จะบอกข้อมูลนี้ ฉันขอแนะนำให้คุณลองสร้างการทำซ้ำที่น้อยที่สุดและสร้างคำถามใหม่สำหรับสถานการณ์เฉพาะของคุณ
GünterZöchbauer

ฉันได้เปิดรับรางวัลสำหรับมัน โปรดดูที่stackoverflow.com/q/48145380/5383669
Sagar Kodte

22

คำสัญญาสามารถ "จัดการ" ได้หลังจากถูกปฏิเสธ นั่นคือเราสามารถเรียกการปฏิเสธการโทรของสัญญาก่อนที่จะให้จัดการจับ พฤติกรรมนี้ค่อนข้างน่ารำคาญสำหรับฉันเพราะสามารถเขียน ...

var promise = new Promise(function(resolve) {
kjjdjf(); // this function does not exist });

... และในกรณีนี้สัญญาถูกปฏิเสธอย่างเงียบ ๆ หากลืมที่จะเพิ่มตัวจัดการการจับรหัสจะยังคงทำงานโดยไม่มีข้อผิดพลาด สิ่งนี้อาจนำไปสู่ข้อผิดพลาดที่เอ้อระเหยและหายาก

ในกรณีของ Node.js มีการพูดถึงการจัดการการปฏิเสธสัญญาเหล่านี้และการรายงานปัญหา นี่นำฉันมาสู่ ES7 async / คอย ลองพิจารณาตัวอย่างนี้:

async function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  let temp = await tempPromise;
  // Assume `changeClothes` also returns a Promise
  if(temp > 20) {
    await changeClothes("warm");
  } else {
    await changeClothes("cold");
  }

  await teethPromise;
}

ในตัวอย่างด้านบนสมมติว่ามีการปฏิเสธว่าฟันสัญญา (ข้อผิดพลาด: ออกจากยาสีฟัน!) ก่อนที่จะได้รับอุณหภูมิจริง ในกรณีนี้จะมีการปฏิเสธสัญญาที่ไม่สามารถจัดการได้จนกว่าจะรอฟันสัญญา

ประเด็นของฉันคือ ... หากเราพิจารณาว่าการปฏิเสธคำสัญญาที่ไม่ได้จัดการเป็นปัญหาสัญญาที่ได้รับการจัดการโดยผู้รอภายหลังอาจได้รับรายงานว่าเป็นข้อบกพร่อง จากนั้นอีกครั้งหากเราพิจารณาการปฏิเสธคำสัญญาที่ไม่ได้จัดการเพื่อไม่เป็นปัญหาบั๊กที่ถูกกฎหมายอาจไม่ได้รับการรายงาน

คิดเกี่ยวกับเรื่องนี้?

สิ่งนี้เกี่ยวข้องกับการสนทนาที่พบในโครงการ Node.js ที่นี่:

ค่าเริ่มต้นพฤติกรรมการตรวจจับการปฏิเสธที่ไม่สามารถจัดการได้

ถ้าคุณเขียนรหัสด้วยวิธีนี้:

function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  return Promise.resolve(tempPromise)
    .then(temp => {
      // Assume `changeClothes` also returns a Promise
      if (temp > 20) {
        return Promise.resolve(changeClothes("warm"));
      } else {
        return Promise.resolve(changeClothes("cold"));
      }
    })
    .then(teethPromise)
    .then(Promise.resolve()); // since the async function returns nothing, ensure it's a resolved promise for `undefined`, unless it's previously rejected
}

เมื่อ getReadyForBed ถูกเรียกใช้มันจะสร้างสัญญาสุดท้าย (ไม่ส่งคืน) พร้อมกันซึ่งจะมีข้อผิดพลาด "ปฏิเสธการจัดการ" แบบเดียวกันกับสัญญาอื่น ๆ (อาจไม่มีอะไรแน่นอนขึ้นอยู่กับเครื่องยนต์) (ฉันคิดว่ามันแปลกมากที่ฟังก์ชั่นของคุณไม่ส่งคืนสิ่งใดซึ่งหมายความว่าฟังก์ชั่น async ของคุณให้คำมั่นว่าจะไม่ได้กำหนด

ถ้าฉันทำสัญญาทันทีโดยไม่ต้องจับและเพิ่มในภายหลังการใช้งาน "ข้อผิดพลาดการปฏิเสธการจัดการ" ส่วนใหญ่จะถอนคำเตือนจริง ๆ เมื่อฉันจัดการในภายหลัง กล่าวอีกนัยหนึ่ง async / คอยไม่เปลี่ยนการสนทนา "ปฏิเสธการจัดการ" ในทางที่ฉันเห็น

เพื่อหลีกเลี่ยงข้อผิดพลาดนี้โปรดเขียนรหัสด้วยวิธีนี้:

async function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  var clothesPromise = tempPromise.then(function(temp) {
    // Assume `changeClothes` also returns a Promise
    if(temp > 20) {
      return changeClothes("warm");
    } else {
      return changeClothes("cold");
    }
  });
  /* Note that clothesPromise resolves to the result of `changeClothes`
     due to Promise "chaining" magic. */

  // Combine promises and await them both
  await Promise.all(teethPromise, clothesPromise);
}

โปรดทราบว่าสิ่งนี้ควรป้องกันการปฏิเสธคำสัญญาที่ไม่สามารถจัดการได้


13

"การคัดค้านคำเตือน: การปฏิเสธสัญญาที่ไม่ได้จัดการจะถูกคัดค้าน"

TLDR: คำสัญญามีresolveและrejectการrejectไม่จับเพื่อจัดการมันจะถูกคัดค้านดังนั้นคุณจะต้องมีcatchระดับสูงสุด


2

ในกรณีของฉันคือสัญญาโดยไม่ปฏิเสธและไม่แก้ไขเพราะฟังก์ชั่นสัญญาของฉันมีข้อยกเว้น ข้อผิดพลาดนี้ทำให้เกิด UnhandledPromiseRejectionWarning message


1

เมื่อฉันยกตัวอย่างสัญญาฉันจะสร้างฟังก์ชันอะซิงโครนัส ถ้าฟังก์ชั่นเป็นไปด้วยดีฉันจะเรียก RESOLVE จากนั้นโฟลว์จะดำเนินต่อไปใน RESOLVE handler ใน THEN หากฟังก์ชั่นล้มเหลวให้ยุติการทำงานโดยเรียก REJECT จากนั้นโฟลว์จะดำเนินการต่อใน CATCH

ใน NodeJs ถูกคัดค้านตัวจัดการการปฏิเสธ ข้อผิดพลาดของคุณเป็นเพียงคำเตือนและฉันอ่านมันภายใน node.js github ฉันพบสิ่งนี้

DEP0018: การปฏิเสธสัญญาที่ไม่สามารถจัดการได้

ประเภท: รันไทม์

การปฏิเสธสัญญาที่ไม่ได้จัดการจะถูกคัดค้าน ในอนาคตการปฏิเสธสัญญาที่ไม่ได้จัดการจะยุติกระบวนการ Node.js ด้วยรหัสออกที่ไม่เป็นศูนย์

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