Một lời từ chối lời hứa chưa được xử lý là gì?


203

Để học Angular 2, tôi đang thử hướng dẫn của họ.

Tôi nhận được một lỗi như thế này:

(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.

Tôi đã trải qua các câu hỏi và câu trả lời khác nhau trong SO nhưng không thể tìm ra "Từ chối lời hứa chưa được xử lý" là gì.

Bất cứ ai có thể đơn giản giải thích cho tôi nó là gì và cũng Error: spawn cmd ENOENTlà gì , khi nó phát sinh và những gì tôi phải kiểm tra để thoát khỏi cảnh báo này?


2
Tôi đã bỏ lỡ câu hỏi này! Tôi rất xin lỗi vì cảnh báo này thật khó hiểu - chúng tôi thực sự đã cải thiện nó trong Node.js mới hơn và chúng tôi sẽ sớm làm cho mọi thứ tốt hơn nhiều!
Benjamin Gruenbaum


@BenjaminGruenbaum, nó đã được sửa chưa? Tôi đã gặp lỗi tương tự trên nút v12.16.1
Em bé

1
@Babydesta tốt, hiện tại chúng tôi hiển thị một lỗi tốt hơn với dấu vết ngăn xếp nhưng chúng tôi vẫn không gặp sự cố nút trên các từ chối chưa xử lý. Chúng tôi có lẽ chỉ cần mở một PR để làm điều đó.
Benjamin Gruenbaum

Câu trả lời:


200

Nguồn gốc của lỗi này nằm ở chỗ mỗi lời hứa được mong đợi sẽ xử lý từ chối lời hứa, tức là có .catch (...) . bạn có thể tránh điều tương tự bằng cách thêm .catch (...) vào một lời hứa trong mã như được đưa ra dưới đây.

ví dụ, hàm PTest () sẽ giải quyết hoặc từ chối lời hứa dựa trên giá trị của biến toàn cục 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");
});

Trong một số trường hợp, thông báo "từ chối lời hứa chưa được xử lý" xuất hiện ngay cả khi chúng tôi có .catch (..) được viết cho lời hứa. Đó là tất cả về cách bạn viết mã của bạn. Đoạn mã sau sẽ tạo ra "từ chối lời hứa chưa được xử lý " mặc dù chúng tôi đang xử lý 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");
});

Sự khác biệt là bạn không xử lý .catch(...)theo chuỗi mà là riêng biệt. Vì một số lý do, công cụ JavaScript coi nó như lời hứa mà không bị từ chối lời hứa.


4
Nó dường như hoạt động, nếu bạn thêm myFunc = myFunct.then...vào ví dụ thứ hai.
einstein

@einstein nó sẽ xuất hiện để hoạt động vì bạn đang tạo lại chuỗi giống như trong ví dụ đầu tiên:var x = foo(); x = x.then(...); x = x.catch(...)
randomsock

4
@einstein Trong ví dụ unchained của bạn, khi bạn nói "Đối với một số lý do Java Script engine xử lý nó như lời hứa mà không từ chối lời hứa un-xử lý", không phải là ngoại lệ này vì và có thể được ném vào .then(() => {...})mà bạn không xử lý? Tôi không nghĩ rằng điều này đang làm điều tương tự như khi bạn xâu chuỗi chúng. Là nó?
Simon Legg

8
@DKG Về điểm thứ hai của bạn, catchlà một cú pháp đường cho then(undefined, onRejected). Vì bạn đã được gọi sau đó trên myfunc và điều đó đã gây ra lỗi, nên nó sẽ không gọi sau đó (không xác định, bị từ chối) trên cùng một lời hứa.
Kevin Lee

1
Thay đổi ở đâu? Tôi đang sử dụng ionic 3 khi tôi nhấn lệnh ionic cordova build andorid cho tôi lỗi này.
Sagar Kodte

34

Đây là khi một Promisehoàn thành với .reject()hoặc một ngoại lệ được ném vào một asyncmã được thực thi và không .catch()xử lý từ chối.

Một lời hứa bị từ chối giống như một ngoại lệ xuất hiện ở điểm vào ứng dụng và khiến trình xử lý lỗi gốc tạo ra đầu ra đó.

Xem thêm


Thay đổi ở đâu? Tôi đang sử dụng ionic 3 khi tôi nhấn lệnh ionic cordova build andorid cho tôi lỗi này.
Sagar Kodte

Khó để nói với thông tin này. Tôi khuyên bạn nên cố gắng tạo một bản sao tối thiểu và tạo một câu hỏi mới cho tình huống cụ thể của bạn.
Günter Zöchbauer

tôi đã mở tiền thưởng cho nó. Vui lòng xem tại nó stackoverflow.com/q/48145380/5383669
Sagar Kodte

22

Lời hứa có thể được "xử lý" sau khi chúng bị từ chối. Đó là, người ta có thể gọi lại cuộc gọi từ chối lời hứa trước khi cung cấp trình xử lý bắt. Hành vi này hơi khó chịu với tôi vì người ta có thể viết ...

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

... Và trong trường hợp này, Promise bị từ chối âm thầm. Nếu một người quên thêm trình xử lý bắt, mã sẽ tiếp tục chạy âm thầm mà không có lỗi. Điều này có thể dẫn đến các lỗi kéo dài và khó tìm.

Trong trường hợp của Node.js, có thảo luận về việc xử lý các từ chối Promise chưa được xử lý này và báo cáo các vấn đề. Điều này đưa tôi đến ES7 async / await. Xem xét ví dụ này:

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;
}

Trong ví dụ trên, giả sử răngPromise đã bị từ chối (Lỗi: hết kem đánh răng!) Trước khi getRoomTem Nhiệt độ được hoàn thành. Trong trường hợp này, sẽ có một từ chối Promise chưa được xử lý cho đến khi chờ đợi răngPromise.

Quan điểm của tôi là ... nếu chúng ta coi các từ chối Promise chưa được xử lý là một vấn đề, thì các Promise sau đó được xử lý bởi một sự chờ đợi có thể vô tình được báo cáo là lỗi. Sau đó, một lần nữa, nếu chúng tôi coi các từ chối Promise chưa được xử lý là không có vấn đề, các lỗi hợp pháp có thể không được báo cáo.

Suy nghĩ về điều này?

Điều này có liên quan đến cuộc thảo luận được tìm thấy trong dự án Node.js tại đây:

Hành vi phát hiện từ chối không được xử lý mặc định

nếu bạn viết mã theo cách này:

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
}

Khi getReadyForBed được gọi, nó sẽ tạo đồng bộ lời hứa (không trả lại) cuối cùng - sẽ có lỗi "từ chối không xử lý" giống như bất kỳ lời hứa nào khác (tất nhiên là không có gì, tùy thuộc vào động cơ). (Tôi thấy rất kỳ lạ khi hàm của bạn không trả về bất cứ thứ gì, điều đó có nghĩa là hàm async của bạn tạo ra một lời hứa không xác định.

Nếu tôi thực hiện Lời hứa ngay bây giờ mà không bắt và thêm một lần sau, hầu hết các triển khai "lỗi từ chối chưa xử lý" sẽ thực sự rút lại cảnh báo khi tôi xử lý sau. Nói cách khác, async / await không làm thay đổi cuộc thảo luận "từ chối không được xử lý" theo bất kỳ cách nào tôi có thể thấy.

để tránh cạm bẫy này, xin vui lòng viết mã theo cách này:

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);
}

Lưu ý rằng điều này sẽ ngăn chặn bất kỳ lời từ chối lời hứa nào.


13

"DeprecationWarning: Unhandled từ chối lời hứa không được tán thành"

TLDR: Một lời hứa có resolvereject, thực hiện rejectmà không nắm bắt được để xử lý nó bị phản đối, vì vậy bạn ít nhất sẽ phải có một catchmức cao nhất.


2

Trong trường hợp của tôi là Promise không từ chối cũng không giải quyết được, bởi vì hàm Promise của tôi đã tạo ra một ngoại lệ. Lỗi này gây ra thông báo UnhandledPromiseRejectionWarning.


1

Khi tôi thực hiện một lời hứa, tôi sẽ tạo ra một hàm không đồng bộ. Nếu chức năng hoạt động tốt thì tôi gọi GIẢI QUYẾT thì luồng tiếp tục trong trình xử lý GIẢI QUYẾT, trong THEN. Nếu chức năng thất bại, sau đó chấm dứt chức năng bằng cách gọi RE DỰ ÁN thì luồng tiếp tục trong CATCH.

Trong NodeJs không được chấp nhận xử lý từ chối. Lỗi của bạn chỉ là một cảnh báo và tôi đọc nó bên trong github của node.js. Tôi đã tìm thấy cái này.

DEP0018: Từ chối lời hứa chưa được xử lý

Loại: Thời gian chạy

Từ chối lời hứa không được chấp nhận bị phản đối. Trong tương lai, các từ chối hứa hẹn không được xử lý sẽ chấm dứt quá trình Node.js với mã thoát khác không.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.