Saya ingin menggunakan janji (asli) di aplikasi frontend saya untuk melakukan permintaan XHR tetapi tanpa semua kesalahan kerangka kerja yang masif.
Saya ingin xhr saya untuk kembali janji tapi ini tidak berhasil (memberi saya: Uncaught TypeError: Promise resolver undefined is not a function
)
function makeXHRRequest (method, url, done) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function() { return new Promise().resolve(); };
xhr.onerror = function() { return new Promise().reject(); };
xhr.send();
}
makeXHRRequest('GET', 'http://example.com')
.then(function (datums) {
console.log(datums);
});
javascript
xmlhttprequest
promise
Anak kucing
sumber
sumber
Jawaban:
Saya berasumsi Anda tahu cara membuat permintaan XHR asli (Anda dapat memoles di sini dan di sini )
Karena browser apa pun yang mendukung janji asli juga akan mendukung
xhr.onload
, kami dapat melewati semuaonReadyStateChange
tindakan buruk tersebut. Mari kita mundur selangkah dan mulai dengan fungsi permintaan XHR dasar menggunakan callback:Hore! Ini tidak melibatkan sesuatu yang sangat rumit (seperti header khusus atau data POST) tetapi cukup untuk membuat kita bergerak maju.
Konstruktor janji
Kita bisa membuat janji seperti ini:
Konstruktor janji mengambil fungsi yang akan melewati dua argumen (sebut saja
resolve
danreject
). Anda dapat menganggap ini sebagai panggilan balik, satu untuk kesuksesan dan satu untuk kegagalan. Contohnya luar biasa, mari perbaruimakeRequest
dengan konstruktor ini:Sekarang kita dapat memanfaatkan kekuatan janji, merantai beberapa panggilan XHR (dan keinginan
.catch
akan memicu kesalahan pada salah satu panggilan):Kami dapat meningkatkan ini lebih jauh, menambahkan params POST / PUT dan header kustom. Mari kita gunakan objek opsi alih-alih beberapa argumen, dengan tanda tangan:
makeRequest
sekarang terlihat seperti ini:Pendekatan yang lebih komprehensif dapat ditemukan di MDN .
Atau, Anda bisa menggunakan API pengambilan ( polyfill ).
sumber
responseType
, otentikasi, kredensial,timeout
... Danparams
objek harus mendukung gumpalan / bufferviews danFormData
instancexhr.status
danxhr.statusText
kesalahan, karena mereka kosong dalam kasus itu.resolve(xhr.response | xhr.responseText);
Di sebagian besar browser repsonse berada di responseText sementara itu.Ini bisa sesederhana kode berikut.
Perlu diingat bahwa kode ini hanya akan memecat
reject
panggilan balik ketikaonerror
dipanggil ( hanya kesalahan jaringan ) dan bukan ketika kode status HTTP menandakan kesalahan. Ini juga akan mengecualikan semua pengecualian lainnya. Menangani itu harus terserah Anda, IMO.Selain itu, disarankan untuk memanggil
reject
callback dengan contohError
dan bukan acara itu sendiri, tetapi demi kesederhanaan, saya pergi apa adanya.Dan memohon bisa jadi ini:
sumber
xhr.send(requestBody)
Bagi siapa saja yang mencari ini sekarang, Anda dapat menggunakan fungsi ambil . Ini memiliki beberapa dukungan yang cukup bagus .
Saya pertama kali menggunakan jawaban @ SomeKittens, tetapi kemudian menemukan
fetch
yang melakukannya untuk saya di luar kotak :)sumber
fetch
fungsi ini, tetapi GitHub telah menerbitkan polyfill .fetch
karena belum mendukung pembatalan.Saya pikir kita bisa membuat jawaban atas jauh lebih fleksibel dan dapat digunakan kembali dengan tidak membuatnya membuat
XMLHttpRequest
objek. Satu-satunya keuntungan dari melakukannya adalah bahwa kita tidak harus menulis sendiri 2 atau 3 baris kode untuk melakukannya, dan itu memiliki kelemahan besar dalam menghilangkan akses kita ke banyak fitur API, seperti mengatur header. Ini juga menyembunyikan properti objek asli dari kode yang seharusnya menangani respons (untuk keberhasilan dan kesalahan). Jadi kita dapat membuat fungsi yang lebih fleksibel, lebih luas diterapkan dengan hanya menerimaXMLHttpRequest
objek sebagai input dan meneruskannya sebagai hasilnya .Fungsi ini mengubah
XMLHttpRequest
objek sewenang-wenang menjadi janji, memperlakukan kode status non-200 sebagai kesalahan secara default:Fungsi ini sangat cocok dengan rantai
Promise
s, tanpa mengorbankan fleksibilitasXMLHttpRequest
API:catch
dihilangkan di atas untuk menjaga kode sampel tetap sederhana. Anda harus selalu memilikinya, dan tentu saja kami dapat:Dan menonaktifkan penanganan kode status HTTP tidak memerlukan banyak perubahan dalam kode:
Kode panggilan kami lebih panjang, tetapi secara konsep, masih sederhana untuk memahami apa yang terjadi. Dan kami tidak perlu membangun kembali seluruh API permintaan web hanya untuk mendukung fitur-fiturnya.
Kami dapat menambahkan beberapa fungsi kenyamanan untuk merapikan kode kami, juga:
Kemudian kode kita menjadi:
sumber
Jawaban jpmc26 cukup dekat dengan sempurna menurut saya. Ini memiliki beberapa kelemahan, meskipun:
POST
-requests untuk mengatur badan permintaan.send
panggilan- krusial tersembunyi di dalam suatu fungsi.Monyet menambal objek xhr menangani masalah ini:
Sekarang penggunaannya sesederhana:
Tentu saja, ini memperkenalkan kelemahan yang berbeda: Penambalan monyet tidak merusak kinerja. Namun ini seharusnya tidak menjadi masalah dengan asumsi bahwa pengguna menunggu terutama untuk hasil xhr, bahwa permintaan itu sendiri membutuhkan pesanan lebih besar daripada mengatur panggilan dan permintaan xhr tidak sering dikirim.
PS: Dan tentu saja jika menargetkan browser modern, gunakan fetch!
PPS: Telah ditunjukkan dalam komentar bahwa metode ini mengubah API standar yang dapat membingungkan. Untuk kejelasan yang lebih baik, seseorang dapat menambal metode yang berbeda ke objek xhr
sendAndGetPromise()
.sumber
send
panggilan aktual tetapi juga dapat membingungkan pembaca yang tahu bahwasend
tidak memiliki nilai balik. Menggunakan panggilan yang lebih eksplisit membuatnya lebih jelas bahwa logika tambahan telah dipanggil. Jawaban saya perlu disesuaikan untuk menangani argumensend
; namun, mungkin lebih baik digunakanfetch
sekarang.