Apa perbedaan antara Ditangguhkan, Berjanji dan Masa Depan dalam JavaScript?


300

Apa perbedaan antara Tangguhan, Janji dan Berjangka?
Apakah ada teori yang disetujui secara umum di balik ketiganya?


11
Saya rasa ini tidak ada hubungannya dengan jQuery ...
BoltClock


8
Saya belum menggunakannya sendiri tetapi di sini ada intro yang cukup bagus di wikipedia en.wikipedia.org/wiki/Futures_and_promises . Meskipun saya tidak sepenuhnya memahami use case dengan benar. Dalam bahasa async event driven seperti javascript. Pada pandangan pertama saya tidak bisa melihat apa yang mereka tawarkan melalui panggilan balik, selain mungkin api yang lebih bersih. Saya akan senang jika seseorang dapat memberikan contoh use case, dan menunjukkan bagaimana konsep ini diterapkan, dan mengapa panggilan balik akan menjadi solusi yang tidak efisien. @ Dur ini tidak ada hubungannya dengan jQuery. Bisakah tag jQuery dihapus tolong
AshHeskes

2
@ jfriend00 tautan luar biasa, mungkin harus dikerjakan menjadi jawaban.
fncomp

Jawaban:


97

Mengingat ketidaksukaan yang jelas untuk bagaimana saya telah mencoba untuk menjawab pertanyaan OP. Jawaban literalnya adalah, janji adalah sesuatu yang dibagikan dengan benda lain, sementara yang ditangguhkan harus dirahasiakan. Terutama, yang ditangguhkan (yang umumnya meluas Janji) dapat menyelesaikan sendiri, sementara janji mungkin tidak dapat melakukannya.

Jika Anda tertarik dengan hal-hal kecil, maka periksa Janji / A + .


Sejauh yang saya ketahui, tujuan menyeluruh adalah untuk meningkatkan kejelasan dan melonggarkan kopling melalui antarmuka standar. Lihat saran bacaan dari @ jfriend00:

Alih-alih secara langsung meneruskan panggilan balik ke fungsi, sesuatu yang dapat mengarah ke antarmuka yang sangat erat, menggunakan janji memungkinkan seseorang untuk memisahkan masalah untuk kode yang sinkron atau tidak sinkron.

Secara pribadi, saya telah menemukan ditangguhkan sangat berguna ketika berhadapan dengan misalnya template yang diisi oleh permintaan asinkron, memuat skrip yang memiliki jaringan dependensi, dan memberikan umpan balik pengguna untuk membentuk data dengan cara yang tidak menghalangi.

Memang, bandingkan bentuk panggilan balik murni dari melakukan sesuatu setelah memuat CodeMirror dalam mode JS secara asinkron (maaf, saya tidak menggunakan jQuery untuk sementara waktu ):

/* assume getScript has signature like: function (path, callback, context) 
   and listens to onload && onreadystatechange */
$(function () {
   getScript('path/to/CodeMirror', getJSMode);

   // onreadystate is not reliable for callback args.
   function getJSMode() {
       getScript('path/to/CodeMirror/mode/javascript/javascript.js', 
           ourAwesomeScript);
   };

   function ourAwesomeScript() {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   };
});

Untuk versi yang dirumuskan janji (sekali lagi, permintaan maaf, saya tidak up to date di jQuery):

/* Assume getScript returns a promise object */
$(function () {
   $.when(
       getScript('path/to/CodeMirror'),
       getScript('path/to/CodeMirror/mode/javascript/javascript.js')
   ).then(function () {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   });
});

Permintaan maaf untuk kode semi-semu, tapi saya harap itu membuat ide inti agak jelas. Pada dasarnya, dengan mengembalikan janji yang terstandarisasi, Anda dapat melewati janji itu, sehingga memungkinkan pengelompokan yang lebih jelas.


10
Meskipun jawaban ini mungkin berguna, itu tidak secara faktual menjawab pertanyaan: yang disebut ditangguhkan adalah masa depan atau janji, tergantung pada implementasinya.
awdz9nld

@ MartinKällman Anda benar! Saya belum mengunjungi ini untuk sementara waktu dan telah belajar sedikit. Saya akan memposting jawaban terpisah di bawah, tetapi tinggalkan ini karena orang-orang tampaknya mendapat manfaat dari contoh penggunaan.
fncomp

@ MartinKällman, dianggap menulis jawaban baru. Namun, saya pikir OP benar-benar ingin tahu untuk apa Janji dan Tangguhan. Jawaban untuk pertanyaan aktualnya adalah, "ditangguhkan dapat menyelesaikan sendiri. AFAIK, teori di balik janji dan ditangguhkan berasal dari [Pemrograman Reaktif Fungsional | haskell.org/haskellwiki/Functional_Reactive_Programming] , yang merupakan teknik untuk meratakan panggilan balik. . "
fncomp

2
Ini sama sekali salah dan contoh Anda mudah dilakukan dengan panggilan balik. Janji bukan tentang agregasi panggilan balik dan decoupling tetapi menyediakan DSL untuk menulis kode async seperti kode sinkronisasi ditulis. Terutama fn(callback, errback)tidak ada yang lebih erat atau kurang bermanfaat dari fn().then(callback, errback)- tapi itu cara yang salah untuk menggunakan janji. Saya terutama membenci $.whencontoh kultus kargo - sama sekali tidak ada alasan Anda tidak dapat memiliki $.whenfungsi yang bekerja dengan callback.
Esailija

Ini tidak menjawab pertanyaan meskipun +1 yang saya bisa tahu apa itu panggilan balik.
Bhojendra Rauniyar

146

Jawaban-jawaban ini, termasuk jawaban yang dipilih, baik untuk memperkenalkan janji konseptual, tapi kurang dalam spesifik dari apa sebenarnya perbedaan dalam terminologi yang timbul ketika menggunakan perpustakaan menerapkan mereka (dan ada yang perbedaan penting).

Karena masih merupakan spec yang berkembang , jawabannya saat ini berasal dari upaya mensurvei kedua referensi (seperti wikipedia ) dan implementasi (seperti jQuery ):

  • Ditangguhkan : Tidak pernah dijelaskan dalam referensi populer, 1 2 3 4 tetapi umumnya digunakan oleh implementasi sebagai wasit dari resolusi janji (implementasi dan ). 5 6 7 resolvereject

    Kadang-kadang ditangguhkan juga merupakan janji (implementasi then), 5 6 kali lain itu dianggap lebih murni untuk memiliki tangguhan hanya mampu resolusi, dan memaksa pengguna untuk mengakses janji untuk menggunakan . 7 then

  • Janji : Kata yang paling lengkap untuk strategi yang dibahas.

    Objek proxy menyimpan hasil fungsi target yang sinkronisitasnya ingin kita abstraksi, ditambah mengekspos thenfungsi yang menerima fungsi target lain dan mengembalikan janji baru. 2

    Contoh dari CommonJS :

    > asyncComputeTheAnswerToEverything()
        .then(addTwo)
        .then(printResult);
    44

     

    Selalu dijelaskan dalam referensi populer, meskipun tidak pernah ditentukan untuk siapa tanggung jawabnya jatuh. 1 2 3 4

    Selalu hadir dalam implementasi populer, dan tidak pernah diberikan resolusi resolusi. 5 6 7

  • Masa Depan : istilah yang tampaknya sudah ketinggalan zaman ditemukan dalam beberapa referensi populer 1 dan setidaknya satu implementasi populer, 8 tetapi tampaknya sedang dihapus dari diskusi dalam preferensi untuk istilah 'janji' 3 dan tidak selalu disebutkan dalam pengantar populer untuk topik tersebut. 9

    Namun, setidaknya satu perpustakaan menggunakan istilah umum untuk abstrak sinkronisasi dan penanganan kesalahan, sambil tidak menyediakan thenfungsionalitas. 10 Tidak jelas apakah menghindari istilah 'janji' itu disengaja, tetapi mungkin pilihan yang baik karena janji dibangun di sekitar 'barang-barang luar'. 2

Referensi

  1. Wikipedia tentang Janji & Berjangka
  2. Janji / spesifikasi A +
  3. Standar DOM tentang Janji
  4. DOM Standard Promises Spec WIP
  5. DOJO Toolkit Ditangguhkan
  6. jQuery Tangguhan
  7. Q
  8. FutureJS
  9. Bagian Javascript fungsional pada Janji
  10. Berjangka dalam Pengujian Integrasi AngularJS

Hal-hal yang berpotensi membingungkan


5
Untuk menambahkan sedikit klarifikasi tentang istilah "Masa Depan" - futures memiliki sejarah panjang di banyak bahasa pemrograman sejak pertengahan 80-an. Dan istilah ini masih digunakan secara luas saat ini, khususnya pada JVM. JavaScript tampaknya memilih untuk menggunakan istilah "Janji" untuk mengartikan sesuatu yang mirip dengan apa yang Jawa maksud dengan "Masa Depan". Scala memisahkan konsep yang sama menjadi "Masa Depan" dan "Janji" untuk merujuk pada pegangan "baca" dan "tulis" dari apa yang oleh pemrogram JavaScript disebut Janji.
Heather Miller

1
Dan tentu saja Microsoft harus datang dengan istilah mereka sendiri untuk itu, jadi dalam C # mereka dipanggilTask
BlueRaja - Danny Pflughoeft

72

Yang benar-benar membuat saya mengklik adalah presentasi oleh Domenic Denicola ini.

Dalam inti github , dia memberikan deskripsi yang paling saya sukai, sangat ringkas:

Inti dari janji-janji itu adalah mengembalikan komposisi fungsional dan kesalahan yang muncul di dunia async.

Dengan kata lain, janji adalah cara yang memungkinkan kita menulis kode asinkron yang hampir mudah untuk ditulis seolah-olah itu sinkron .

Pertimbangkan contoh ini, dengan janji:

getTweetsFor("domenic") // promise-returning async function
    .then(function (tweets) {
        var shortUrls = parseTweetsForUrls(tweets);
        var mostRecentShortUrl = shortUrls[0];
        return expandUrlUsingTwitterApi(mostRecentShortUrl); // promise-returning async function
    })
    .then(doHttpRequest) // promise-returning async function
    .then(
        function (responseBody) {
            console.log("Most recent link text:", responseBody);
        },
        function (error) {
            console.error("Error with the twitterverse:", error);
        }
    );

Ini berfungsi seolah-olah Anda sedang menulis kode sinkron ini:

try {
    var tweets = getTweetsFor("domenic"); // blocking
    var shortUrls = parseTweetsForUrls(tweets);
    var mostRecentShortUrl = shortUrls[0];
    var responseBody = doHttpRequest(expandUrlUsingTwitterApi(mostRecentShortUrl)); // blocking x 2
    console.log("Most recent link text:", responseBody);
} catch (error) {
    console.error("Error with the twitterverse: ", error);
}

(Jika ini masih terdengar rumit, tonton presentasi itu!)

Mengenai Ditangguhkan, itu cara .resolve()atau .reject()janji. Dalam spec Janji / B , itu disebut .defer(). Di jQuery, itu $.Deferred().

Harap dicatat bahwa, sejauh yang saya tahu, implementasi Janji di jQuery rusak (lihat intinya), setidaknya pada jQuery 1.8.2.
Seharusnya mengimplementasikan Promises / A thenables , tetapi Anda tidak mendapatkan penanganan kesalahan yang benar, Anda harus, dalam arti bahwa seluruh fungsi "async try / catch" tidak akan berfungsi. Sangat disayangkan, karena memiliki "coba / tangkap" dengan kode async benar-benar keren.

Jika Anda akan menggunakan Janji (Anda harus mencobanya dengan kode Anda sendiri!), Gunakan Q Kris Kowal . Versi jQuery hanyalah beberapa agregator panggilan balik untuk menulis kode jQuery yang lebih bersih, tetapi tidak mengerti intinya.

Mengenai Masa Depan, saya tidak tahu, saya belum melihatnya di API apa pun.

Sunting: Pembicaraan youtube Domenic Denicola di Janji dari komentar @Farm di bawah ini.

Kutipan dari Michael Jackson (ya, Michael Jackson ) dari video:

Saya ingin Anda membakar frasa ini dalam pikiran Anda: Janji adalah nilai yang tidak sinkron .

Ini adalah deskripsi yang sangat baik: janji seperti variabel dari masa depan - referensi kelas satu untuk sesuatu yang, pada titik tertentu, akan ada (atau terjadi).


5
Penjelasan hebat Futures (sekarang diimplementasikan di DOM!) Oleh anggota tim inti W3 dan Chrome dapat ditemukan di sini: xanthir.com/b4PY0
oligofren

1
@oligofren Terima kasih atas tautannya, sepertinya bagus! Ngomong-ngomong, lol favicon yang secara misterius menyebalkan.
Camilo Martin

1
Jawaban ini membutuhkan lebih banyak upvotes. Itu harus dinilai lebih tinggi daripada jawaban yang diterima IMO.
Chev

1
Pembicaraan youtube Domenic Denicola di Promises: youtube.com/watch?v=hf1T_AONQJU
Farm

@Pertanian Hebat! Saya akan menambahkan itu ke jawabannya.
Camilo Martin

32

Sebuah Janji merupakan proxy untuk nilai belum tentu diketahui kapan janji itu dibuat. Hal ini memungkinkan Anda untuk mengaitkan penangan ke nilai keberhasilan akhir atau alasan kegagalan tindakan asinkron. Ini memungkinkan metode asinkron mengembalikan nilai seperti metode sinkron: alih-alih nilai akhir, metode asinkron mengembalikan janji memiliki nilai di beberapa titik di masa mendatang.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

The deferred.promise()Metode memungkinkan fungsi asynchronous untuk mencegah kode lain dari campur dengan kemajuan atau status permintaan internal. Janji hanya memperlihatkan metode Ditangguhkan yang diperlukan untuk melampirkan penangan tambahan atau menentukan negara ( kemudian, dilakukan, gagal, selalu, pipa, kemajuan, negara dan janji ), tetapi bukan orang-orang yang mengubah negara ( tekad, tolak, beri tahu, tekad Dengan, tolak dengan, dan beri tahu ).

Jika target disediakan, deferred.promise()akan melampirkan metode ke atasnya dan kemudian mengembalikan objek ini daripada membuat yang baru. Ini bisa berguna untuk melampirkan perilaku Janji ke objek yang sudah ada.

Jika Anda membuat Ditangguhkan, simpan referensi ke Ditangguhkan sehingga dapat diselesaikan atau ditolak di beberapa titik. Kembalikan hanya objek Janji melalui deferred.promise () sehingga kode lain dapat mendaftarkan panggilan balik atau memeriksa keadaan saat ini.

Secara sederhana kita dapat mengatakan bahwa Janji mewakili nilai yang belum diketahui di mana sebagai Tangguhan mewakili pekerjaan yang belum selesai.


masukkan deskripsi gambar di sini


1
ditambah 1 untuk representasi bagan. Bravisimo !! ^ _ ^
Ashok MA

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.