Apa itu penolakan janji yang tidak tertangani?


203

Untuk mempelajari Angular 2, saya mencoba tutorial mereka.

Saya mendapatkan kesalahan seperti ini:

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

Saya telah melalui berbagai pertanyaan dan jawaban dalam SO tetapi tidak dapat menemukan apa itu "Penolakan Janji yang Tidak Ditangani".

Adakah yang bisa dengan mudah menjelaskan kepada saya apa itu dan juga apa Error: spawn cmd ENOENTitu, ketika itu muncul dan apa yang harus saya periksa untuk menyingkirkan peringatan ini?


2
Saya melewatkan pertanyaan ini! Saya sangat menyesal atas peringatan ini yang membingungkan - kami benar-benar memperbaikinya di Node.js yang lebih baru dan kami membuat semuanya menjadi jauh lebih baik segera!
Benjamin Gruenbaum


@BenjaminGruenbaum, apakah sudah diperbaiki? Saya mendapat kesalahan yang sama pada simpul v12.16.1
Baby

1
@Babydesta yah, kami menunjukkan kesalahan yang lebih baik sekarang dengan jejak tumpukan tetapi kami masih tidak menabrak simpul pada penolakan yang tidak ditangani. Kami mungkin hanya perlu membuka PR untuk melakukan itu.
Benjamin Gruenbaum

Jawaban:


200

Asal usul kesalahan ini terletak pada kenyataan bahwa masing-masing dan setiap janji diharapkan untuk menangani penolakan janji yaitu memiliki .catch (...) . Anda dapat menghindari hal yang sama dengan menambahkan .catch (...) ke janji dalam kode seperti yang diberikan di bawah ini.

misalnya, fungsi PTest () akan menyelesaikan atau menolak janji berdasarkan nilai variabel global 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");
});

Dalam beberapa kasus, pesan "penolakan janji tak tertangani" datang bahkan jika kita memiliki .catch (..) yang ditulis untuk janji. Ini semua tentang bagaimana Anda menulis kode Anda. Kode berikut akan menghasilkan "penolakan janji tidak tertangani" meskipun kami sedang menangani 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");
});

Perbedaannya adalah bahwa Anda tidak menangani .catch(...)sebagai rantai tetapi terpisah. Untuk beberapa alasan mesin JavaScript memperlakukannya sebagai janji tanpa penolakan janji yang tidak ditangani.


4
Tampaknya berfungsi, jika Anda menambahkan myFunc = myFunct.then...dalam contoh kedua.
Einstein

@einstein tampaknya akan berfungsi karena Anda membuat ulang rantai yang sama seperti pada contoh pertama:var x = foo(); x = x.then(...); x = x.catch(...)
randomsock

4
@einstein Dalam contoh Anda yang tidak dirantai, ketika Anda mengatakan "Untuk beberapa alasan mesin Java Script memperlakukannya sebagai janji tanpa penolakan janji yang tidak ditangani", bukankah ini karena dan pengecualian dapat dilemparkan ke tempat .then(() => {...})yang tidak Anda tangani? Saya tidak berpikir ini melakukan hal yang sama seperti ketika Anda rantai mereka. Apakah itu?
Simon Legg

8
@DKG Mengenai poin kedua Anda, catchadalah gula sintaksis untuk then(undefined, onRejected). Karena Anda sudah menelepon maka pada fungsi saya dan itu memicu kesalahan, itu tidak akan memanggil kemudian (tidak didefinisikan, onRejected) pada janji yang sama lagi.
Kevin Lee

1
Di mana harus berubah? Saya menggunakan ionic 3 ketika saya menekan ionic cordova build andorid command memberi saya kesalahan ini.
Sagar Kodte

34

Ini adalah ketika Promiseselesai dengan .reject()atau pengecualian dilemparkan ke dalam asynckode yang dieksekusi dan tidak ada yang .catch()menangani penolakan.

Janji yang ditolak seperti pengecualian yang muncul ke titik masuk aplikasi dan menyebabkan root error handler untuk menghasilkan output itu.

Lihat juga


Di mana harus berubah? Saya menggunakan ionic 3 ketika saya menekan ionic cordova build andorid command memberi saya kesalahan ini.
Sagar Kodte

Sulit dikatakan dengan informasi ini. Saya sarankan Anda mencoba membuat reproduksi minimal dan membuat pertanyaan baru untuk situasi spesifik Anda.
Günter Zöchbauer

saya telah membuka karunia untuk itu. Silakan lihat itu stackoverflow.com/q/48145380/5383669
Sagar Kodte

22

Janji dapat "ditangani" setelah ditolak. Artinya, seseorang dapat memanggil callback tolak janji sebelum memberikan catch handler. Perilaku ini sedikit mengganggu saya karena orang dapat menulis ...

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

... dan dalam hal ini, Janji itu ditolak secara diam-diam. Jika seseorang lupa menambahkan catch handler, kode akan terus berjalan tanpa kesalahan. Ini dapat menyebabkan bug yang bertahan dan sulit ditemukan.

Dalam kasus Node.js, ada pembicaraan tentang penanganan penolakan Janji yang tidak tertangani ini dan melaporkan masalahnya. Ini membawa saya ke ES7 async / menunggu. Pertimbangkan contoh ini:

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

Dalam contoh di atas, misalkan toothPromise ditolak (Kesalahan: kehabisan pasta gigi!) Sebelum getRoomTemperature dipenuhi. Dalam hal ini, akan ada penolakan Janji yang tidak tertangani sampai menunggu gigi Janji.

Maksud saya adalah ini ... jika kita menganggap penolakan Janji yang tidak tertangani menjadi masalah, Janji yang nanti ditangani dengan menunggu mungkin akan dilaporkan secara tidak sengaja sebagai bug. Kemudian lagi, jika kami menganggap penolakan Janji yang tidak tertangani tidak menjadi masalah, bug yang sah mungkin tidak dilaporkan.

Pikiran tentang ini?

Ini terkait dengan diskusi yang ditemukan dalam proyek Node.js di sini:

Perilaku Deteksi Penolakan Tanpa Penanganan Default

jika Anda menulis kode dengan cara ini:

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
}

Ketika getReadyForBed dipanggil, ia akan secara sinkron membuat janji terakhir (tidak dikembalikan) - yang akan memiliki kesalahan "penolakan tertangan" yang sama dengan janji lainnya (bisa jadi tidak ada apa-apa, tentu saja, tergantung pada mesinnya). (Saya merasa sangat aneh fungsi Anda tidak mengembalikan apa pun, yang berarti fungsi async Anda menghasilkan janji untuk tidak terdefinisi.

Jika saya membuat Janji sekarang tanpa tangkapan, dan menambahkannya nanti, sebagian besar implementasi "kesalahan penolakan tidak tertangani" sebenarnya akan menarik kembali peringatan ketika saya nanti menanganinya. Dengan kata lain, async / await tidak mengubah diskusi "penolakan yang tidak ditangani" dengan cara apa pun yang dapat saya lihat.

untuk menghindari jebakan ini, harap tulis kode seperti ini:

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

Perhatikan bahwa ini harus mencegah penolakan janji yang tidak ditangani.


13

"DeprecationWarning: tertangani penolakan janji yang usang"

TLDR: Sebuah janji telah resolvedan reject, melakukan rejecttanpa tangkapan untuk mengatasinya sudah usang, sehingga Anda harus setidaknya memiliki catchdi tingkat atas.


2

Dalam kasus saya adalah Janji tanpa menolak atau menyelesaikan, karena fungsi Janji saya melemparkan pengecualian. Kesalahan ini menyebabkan pesan UnhandledPromiseRejectionWarning.


1

Ketika saya instantiate janji, saya akan menghasilkan fungsi asinkron. Jika fungsinya berjalan dengan baik maka saya memanggil RESOLVE maka aliran berlanjut di RESOLVE handler, di THEN. Jika fungsi gagal, maka akhiri fungsi dengan memanggil TOLAK lalu aliran berlanjut di CATCH.

Di NodeJs sudah usang penangan penolakan. Kesalahan Anda hanyalah peringatan dan saya membacanya di dalam node.js github. Aku menemukan ini.

DEP0018: penolakan janji yang tidak ditangani

Jenis: Runtime

Penolakan janji yang tidak ditangani sudah ditinggalkan. Di masa depan, penolakan janji yang tidak ditangani akan menghentikan proses Node.js dengan kode keluar yang tidak nol.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.