Penolakan tidak disebarkan dengan janji berantai
P粉193307465
P粉193307465 2023-10-23 17:50:47
0
2
2899

Saya tidak faham mengapa penolakan tidak melalui rantaian janji, saya harap seseorang boleh membantu saya memahami mengapa. Bagi saya, melampirkan fungsi pada urutan janji bermakna saya bergantung pada niat janji asal untuk ditunaikan. Ini sukar untuk dijelaskan, jadi izinkan saya menunjukkan contoh kod masalah saya dahulu. (Nota: Contoh ini menggunakan Node dan modul nod tertunda. Saya menguji ini menggunakan Dojo 1.8.3 dan mendapat keputusan yang sama)

var d = require("deferred");

var d1 = d();

var promise1 = d1.promise.then(
    function(wins) { console.log('promise1 resolved'); return wins;},
    function(err) { console.log('promise1 rejected'); return err;});
var promise2 = promise1.then(
    function(wins) { console.log('promise2 resolved'); return wins;},
    function(err) { console.log('promise2 rejected'); return err;});
var promise3 = promise2.then(
    function(wins) { console.log('promise3 resolved'); return wins;},
    function(err) { console.log('promise3 rejected'); return err;});
d1.reject(new Error());

Hasil menjalankan ini adalah output ini:

promise1 rejected
promise2 resolved
promise3 resolved

Bagi saya, keputusan ini tidak masuk akal. Dengan melampirkan pada rantai Janji ini, masing-masing menunjukkan niat bahawa ia akan bergantung pada resolusi yang berjaya d1 dan keputusan yang diluluskan sepanjang rantaian. Jika janji dalam promise1 tidak menerima nilai menang, tetapi nilai ralat dalam pengendali ralatnya, bagaimana janji seterusnya dalam rantai boleh memanggil fungsi kejayaannya? Ia tidak boleh memberikan nilai yang bermakna kepada Janji seterusnya kerana ia tidak mendapat nilai itu sendiri.

Saya boleh menerangkan idea saya dengan cara lain: Terdapat tiga orang: John, Ginger dan Bob. John memiliki kedai widget. Ginger masuk ke dalam kedainya dan meminta beg widget dalam pelbagai warna. Dia tidak mempunyai stok, jadi dia menghantar permintaan kepada peniaganya untuk menghantarnya kepadanya. Sementara itu, dia memberi Ginger cek hujan, mengatakan dia berhutang dengan beg widget itu. Bob melihat Ginger mendapatkan widget dan memintanya mendapatkan widget biru apabila dia selesai menggunakannya. Dia bersetuju dan memberinya nota yang mengatakan dia akan bersetuju. Kini, peniaga John tidak dapat mencari sebarang widget dalam bekalan mereka dan pengeluar tidak lagi membuat widget, jadi mereka memberitahu John, yang seterusnya memberitahu Ginger bahawa dia tidak boleh mendapatkan widget itu. Bagaimanakah Bob boleh mendapatkan widget biru daripada Ginger sedangkan dia sendiri tidak mendapat apa-apa?

Perspektif ketiga saya yang lebih realistik mengenai isu ini ialah ini. Katakan saya mempunyai dua nilai yang saya ingin kemas kini ke pangkalan data. Satu bergantung pada id yang lain, tetapi saya tidak boleh mendapatkan id sehingga saya memasukkannya ke dalam pangkalan data dan mendapatkan hasilnya. Selain itu, sisipan pertama bergantung pada pertanyaan pangkalan data. Janji yang dikembalikan oleh panggilan pangkalan data ialah apa yang saya gunakan untuk merantai kedua-dua panggilan ke dalam urutan.

var promise = db.query({parent_id: value});
promise.then(function(query_result) {
    var first_value = {
        parent_id: query_result[0].parent_id
    }
    var promise = db.put(first_value);
    promise.then(function(first_value_result) {
        var second_value = {
            reference_to_first_value_id: first_value_result.id
        }
        var promise = db.put(second_value);
        promise.then(function(second_value_result) {
            values_successfully_entered();
        }, function(err) { return err });
    }, function(err) { return err });
}, function(err) { return err });

Kini, dalam kes ini, jika db.query gagal, ia akan memanggil fungsi err yang pertama kemudian. Tetapi kemudian ia memanggil fungsi kejayaan janji seterusnya. Walaupun Janji ini menjangkakan hasil nilai pertama, ia mendapat mesej ralat daripada fungsi pengendalian ralatnya.

Jadi, soalan saya ialah, jika saya perlu menguji ralat dalam fungsi kejayaan, mengapa saya mempunyai fungsi pengendalian ralat?

Maaf, siaran ini terlalu panjang. Saya tidak tahu bagaimana untuk menerangkannya dengan cara lain.

Kemas kini dan Pembetulan

(Nota: Saya telah memadamkan balasan yang telah saya buat untuk beberapa ulasan. Jadi jika seseorang mengulas pada balasan saya, ulasan mereka mungkin muncul di luar konteks sekarang kerana saya telah memadamkannya. Maaf tentang itu, Saya Cuba untuk mengekalkannya sesingkat-singkatnya mungkin)

Terima kasih semua atas balasan anda. Saya terlebih dahulu ingin memohon maaf kepada semua orang kerana betapa teruknya soalan saya ditulis, terutamanya pseudokod saya. Saya agak terlalu agresif dalam cuba untuk memastikan ia pendek.

Terima kasih atas jawapan Bergi, saya rasa saya mendapati ralat dalam logik saya. Saya fikir saya mungkin terlepas pandang satu lagi isu yang menyebabkan masalah yang saya hadapi. Ini mungkin menyebabkan rantaian janji berfungsi secara berbeza daripada yang saya fikirkan. Saya masih menguji elemen kod yang berbeza, jadi saya tidak dapat membentuk soalan yang betul untuk melihat apa yang saya lakukan salah. Walau bagaimanapun, saya ingin mengemas kini semua orang tentang situasi ini dan terima kasih atas bantuan anda.

P粉193307465
P粉193307465

membalas semua(2)
P粉155710425

@Jordan Pertama sekali, seperti yang dinyatakan oleh pengulas, contoh pertama anda pasti akan menghasilkan hasil yang anda jangkakan apabila menggunakan perpustakaan yang malas:

promise1 rejected
promise2 rejected
promise3 rejected

Kedua, walaupun ia menghasilkan output yang anda cadangkan, ia tidak menjejaskan aliran pelaksanaan coretan kod kedua, yang agak berbeza dan lebih seperti:

promise.then(function(first_value) {
    console.log('promise1 resolved');
    var promise = db.put(first_value);
    promise.then(function (second_value) {
         console.log('promise2 resolved');
         var promise = db.put(second_value);
         promise.then(
             function (wins) { console.log('promise3 resolved'); },
             function (err) { console.log('promise3 rejected'); return err; });
    }, function (err) { console.log('promise2 rejected'); return err;});
}, function (err) { console.log('promise1 rejected'); return err});

Dan, jika janji pertama ditolak, hanya keluaran:

promise1 rejected

Walau bagaimanapun (mencapai bahagian yang menyeronokkan) malah perpustakaan tertunda pasti kembali 3 x returned,大多数其他承诺库将返回 1 x returned, 2 x 已解决 (yang membawa kepada andaian bahawa anda mendapat keputusan ini dengan menggunakan beberapa perpustakaan Promise yang lain).

Juga mengelirukan, perpustakaan lain berkelakuan lebih betul. Biar saya jelaskan.

Dalam dunia segerak, rakan sejawat untuk "penolakan janji" ialah 抛出。因此从语义上讲,同步中的异步 deferred.reject(new Error()) 等于 throw new Error(). Dalam contoh anda, anda tidak membuang ralat dalam panggilan balik segerak, anda hanya mengembalikannya, jadi anda beralih kepada aliran kejayaan di mana ralat adalah nilai kejayaan. Untuk memastikan penolakan berjalan lebih jauh, anda perlu membuang semula ralat:

function (err) { console.log('promise1 rejected'); throw err; });

Sekarang persoalannya ialah, mengapa perpustakaan kelewatan menganggap ralat yang dikembalikan sebagai penolakan?

Sebabnya, penolakan dalam kerja tertangguh sedikit berbeza. Dalam lib tertunda, peraturannya ialah: Apabila kejadian ralat berlaku, janji ditolak , jadi walaupun anda melaksanakan panggilan balik deferred.resolve(new Error()) 它也会起作用如 deferred.reject(new Error()) ,如果你尝试执行 deferred.reject(notAnError) ,它会抛出一个异常,表示该 Promise 只能被拒绝有错误的实例。这清楚地表明了为什么从 then ralat yang dikembalikan menolak janji.

Terdapat beberapa alasan yang sah di sebalik logik

tunda, tetapi ia masih tidak sepadan dengan cara throw berfungsi dalam JavaScript, jadi tingkah laku ini dijadualkan berubah dalam keluaran v0.7 yang tertunda.

Ringkasan ringkas:

Untuk mengelakkan kekeliruan dan keputusan yang tidak dijangka, ikut sahaja peraturan amalan yang baik:

  1. Sentiasa menolak janji dengan contoh yang salah (mengikut peraturan dunia segerak, di mana membuang nilai yang tidak salah dianggap amalan buruk).
  2. Baling ralat melalui panggilan balik penyegerakan penolakan (memulangkan ralat tidak menjamin penolakan).

Patuhi perkara di atas dan anda akan mendapat keputusan yang konsisten dan dijangka dalam perpustakaan tertunda dan perpustakaan Promise popular yang lain.

P粉376738875

Tidak. Perkara yang anda huraikan bukanlah rantaian, tetapi hanya menambahkan semua panggilan balik pada d1。然而,如果您想使用 then 链接某些内容,promise2 的结果取决于 promise1 的分辨率以及 promise1 的分辨率以及 然后panggilan balik yang mengendalikannya.

Dokumentasi menyatakan:

.then 方法通常根据 Promises 来看待/A 规范(或者更严格的Promsises/A+ )。这意味着回调 shell 返回的 Promise 将被同化为 Promise2 的解析,如果没有成功/错误处理程序,相应的结果将直接传递给 Promise2 kod> - jadi anda boleh meninggalkan pengendali untuk menyebarkan ralat.

Walau bagaimanapun, jika ralat diuruskan, promise2 yang terhasil dianggap tetap dan akan dipenuhi dengan nilai tersebut. Jika anda tidak mahu perkara ini berlaku, anda mesti promise2 被视为已修复,并将用该值来实现。如果您不希望出现这种情况,则必须重新抛出melempar semula ralat sama seperti dalam klausa cuba-tangkap. Sebagai alternatif, anda boleh mengembalikan janji yang ditolak (tertunda) daripada pengendali. Tidak pasti apakah penolakan Dojo, tetapi:

var d1 = d();

var promise1 = d1.promise.then(
    function(wins) { console.log('promise1 resolved'); return wins;},
    function(err) { console.log('promise1 rejected'); throw err;});
var promise2 = promise1.then(
    function(wins) { console.log('promise2 resolved'); return wins;},
    function(err) { console.log('promise2 rejected'); throw err;});
var promise3 = promise2.then(
    function(wins) { console.log('promise3 resolved'); return wins;},
    function(err) { console.log('promise3 rejected'); throw err;});
d1.reject(new Error());

Dia sepatutnya tidak boleh. Tanpa pengendali ralat, dia hanya akan melihat mesej bahawa tiada widget yang tinggal ((dari John) daripada Ginger Walau bagaimanapun, jika Ginger menetapkan pengendali ralat untuk situasi ini, jika John atau peniaganya Tanpa widget biru yang tinggal, dia masih boleh menunaikan janjinya untuk memberikan Bob widget hijau dari kabinnya sendiri

.

Untuk menukar panggilan balik ralat kepada meta, kembalikan ralat daripada pengendali seperti berkata "Jika tiada widget yang tinggal, berikan sahaja komen kepadanya bahawa tiada widget yang tinggal - ini adalah sama dengan widget yang diperlukan baik".

...maksudnya ralat telah diuruskan di situ. Jika tidak, tinggalkan sahaja panggilan balik ralat. BTW, panggilan balik kejayaan anda tidak 返回 janji yang mereka buat, jadi ia kelihatan tidak berguna. Yang betul ialah:

var promise = db.query({parent_id: value});
promise.then(function(query_result) {
    var first_value = {
        parent_id: query_result[0].parent_id
    }
    var promise = db.put(first_value);
    return promise.then(function(first_value_result) {
        var second_value = {
            reference_to_first_value_id: first_value_result.id
        }
        var promise = db.put(second_value);
        return promise.then(function(second_value_result) {
            return values_successfully_entered();
        });
    });
});

Atau, kerana anda tidak memerlukan penutupan untuk mengakses nilai hasil panggilan balik sebelumnya, malah:

db.query({parent_id: value}).then(function(query_result) {
    return db.put({
        parent_id: query_result[0].parent_id
    });
}).then(function(first_value_result) {
    return db.put({
        reference_to_first_value_id: first_value_result.id
    });
}.then(values_successfully_entered);
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan