Bisakah janji memiliki beberapa argumen untuk dipenuhi?

127

Saya mengikuti spec di sini dan saya tidak yakin apakah itu memungkinkan onFulfilled untuk dipanggil dengan beberapa argumen. Sebagai contoh:

promise = new Promise(function(onFulfilled, onRejected){
    onFulfilled('arg1', 'arg2');
})

sedemikian rupa sehingga kode saya:

promise.then(function(arg1, arg2){
    // ....
});

akan menerima keduanya arg1dan arg2?

Saya tidak peduli tentang bagaimana implementasi janji-janji spesifik melakukannya, saya ingin mengikuti spesifikasi w3c untuk janji-janji erat.

badunk
sumber
Sebagai petunjuk, saya menemukan bahwa menggunakan github.com/then/promise (yang merupakan implementasi barebones) menunjukkan bahwa itu sebenarnya tidak memberikan argumen ke-2
badunk
2
Anda ingin menggunakan Bluebird dengan .spread. - juga, berhentilah memperhatikan spec, spec adalah tentang interop antara implementasi dan minimal oleh desain.
Benjamin Gruenbaum

Jawaban:

130

Saya mengikuti spec di sini dan saya tidak yakin apakah itu memungkinkan onFulfilled untuk dipanggil dengan beberapa argumen.

Tidak, hanya parameter pertama yang akan diperlakukan sebagai nilai resolusi di konstruktor janji. Anda dapat menyelesaikan dengan nilai komposit seperti objek atau array.

Saya tidak peduli tentang bagaimana implementasi janji-janji spesifik melakukannya, saya ingin mengikuti spesifikasi w3c untuk janji-janji erat.

Di situlah saya yakin Anda salah. Spesifikasi ini dirancang agar minimal dan dibangun untuk beroperasi antara perpustakaan janji. Idenya adalah untuk memiliki subset yang masa depan DOM misalnya dapat andal digunakan dan perpustakaan dapat mengkonsumsi. Implementasi yang dijanjikan melakukan apa yang Anda minta .spreaduntuk sementara waktu sekarang. Sebagai contoh:

Promise.try(function(){
    return ["Hello","World","!"];
}).spread(function(a,b,c){
    console.log(a,b+c); // "Hello World!";
});

Dengan Bluebird . Salah satu solusi jika Anda ingin fungsi ini adalah dengan polyfill.

if (!Promise.prototype.spread) {
    Promise.prototype.spread = function (fn) {
        return this.then(function (args) {
            return Promise.all(args); // wait for all
        }).then(function(args){
         //this is always undefined in A+ complaint, but just in case
            return fn.apply(this, args); 
        });
    };
}

Ini memungkinkan Anda melakukan:

Promise.resolve(null).then(function(){
    return ["Hello","World","!"]; 
}).spread(function(a,b,c){
    console.log(a,b+c);    
});

Dengan janji-janji asli tenang biola . Atau gunakan spread yang sekarang (2018) biasa di browser:

Promise.resolve(["Hello","World","!"]).then(([a,b,c]) => {
  console.log(a,b+c);    
});

Atau dengan menunggu:

let [a, b, c] = await Promise.resolve(['hello', 'world', '!']);
Benjamin Gruenbaum
sumber
2
Perhatikan bahwa perpustakaan lain (seperti Q) juga mendukung .spreadseperti Bluebird - alasannya tidak ada dalam spesifikasi adalah bahwa menjaga spesifikasi minimal benar-benar merupakan masalah besar untuk memungkinkan interop antara kode dan perpustakaan.
Benjamin Gruenbaum
Catatan kedua - Anda mungkin ingin memanggil Promise.allarray sebelum menerapkan fungsi daripada hanya .thenuntuk menangani beberapa perpustakaan gula menyediakan. Itu tidak wajib, tapi itu lucu.
Benjamin Gruenbaum
1
Promies.all wajib dengan implementasi Anda, meskipun Anda bisa saja mengubah implementasinya kereturn Promise.all(args).then(function(args){return fn.apply(this, args);})
Esailija
14
spreadadalah pengganti sementara. ES6 memperkenalkan destrukturisasi dan operator sisanya / penyebaran, yang menghilangkan kebutuhan untuk spreadlangsung. .then(([a, b, c]) => {})
Kris Kowal
3
@KrisKowal Perhatikan bahwa .spread () secara implisit tidak .all () tetapi sintaksis penghancuran ES6 tidak -> bluebirdjs.com/docs/api/spread.html
Gomino
66

Anda dapat menggunakan perusakan E6:

Destrukturisasi objek:

promise = new Promise(function(onFulfilled, onRejected){
    onFulfilled({arg1: value1, arg2: value2});
})

promise.then(({arg1, arg2}) => {
    // ....
});

Perusakan susunan:

promise = new Promise(function(onFulfilled, onRejected){
    onFulfilled([value1, value2]);
})

promise.then(([arg1, arg2]) => {
    // ....
});
Wookiem
sumber
3
Contoh akan menyenangkan dan bermanfaat dengan jawaban ini!
Rahul Verma
19

Nilai pemenuhan janji sejajar dengan nilai balik suatu fungsi dan alasan penolakan janji sejajar dengan pengecualian yang dilemparkan dari suatu fungsi. Fungsi tidak dapat mengembalikan beberapa nilai sehingga janji tidak boleh memiliki lebih dari 1 nilai pemenuhan.

Esailija
sumber
4

Sejauh yang saya tahu membaca spesifikasi ES6 Promise dan spesifikasi janji standar, tidak ada klausul yang mencegah implementasi menangani kasus ini - namun tidak diterapkan di perpustakaan berikut:

Saya berasumsi alasan mereka menghilangkan penyelesaian multi-arg adalah untuk membuat urutan perubahan lebih ringkas (yaitu karena Anda hanya dapat mengembalikan satu nilai dalam suatu fungsi, itu akan membuat aliran kontrol menjadi kurang intuitif) Contoh:

new Promise(function(resolve, reject) {
   return resolve(5, 4);
})
.then(function(x,y) {
   console.log(y);
   return x; //we can only return 1 value here so the next then will only have 1 argument
})
.then(function(x,y) {
    console.log(y);
});
megawac
sumber
8
Q tidak mendukung resolusi multi-nilai karena janji berfungsi sebagai proksi untuk hasil pemanggilan fungsi tetapi juga dapat proksi untuk objek jarak jauh. Dalam kedua kasus ini, array adalah satu-satunya representasi yang masuk akal dari nilai gabungan. Dengan tambahan destructing dan argumen "spread" di ES6, sintaks menjadi sangat bagus. Metode "spread" adalah pengganti sementara.
Kris Kowal
Yah, Anda selalu bisa return Promise.of(x, y)bukannya nilai skalar dari thencallback.
Bergi
2

Berikut ini adalah solusi CoffeeScript.

Saya sedang mencari solusi yang sama dan menemukan seomething sangat menikung dari jawaban ini: Menolak janji dengan beberapa argumen (seperti $ http) di AngularJS

jawaban orang ini, Florian

promise = deferred.promise

promise.success = (fn) ->
  promise.then (data) ->
   fn(data.payload, data.status, {additional: 42})
  return promise

promise.error = (fn) ->
  promise.then null, (err) ->
    fn(err)
  return promise

return promise 

Dan untuk menggunakannya:

service.get().success (arg1, arg2, arg3) ->
    # => arg1 is data.payload, arg2 is data.status, arg3 is the additional object
service.get().error (err) ->
    # => err
Val Entin
sumber
Harus ->menjadi =>?
SherylHohman
1
@ SherylHohman Kembali pada hari-hari di tahun 2015 ini ditulis dengan CoffeeScript ( coffeescript.org/#introduction ) dan bukan sintaks ES6. Panah sederhana adalah fungsi sederhana dan panah lemak hampir sama dengan ES6 (saya kira panah lemak ES6 telah lebih atau kurang dipinjam dari CoffeScript).
Val Entin
@SherylHohman Jangan ragu untuk mengedit posting di ECMA jika Anda mau.
Val Entin
Terimakasih atas tanggapan Anda. Saya akan mengedit hanya untuk mengklarifikasi bahwa ini adalah solusi skrip kopi. Dengan itu, jawaban Anda adalah apa adanya & mungkin berguna untuk basis kode CoffeeScript. Terima kasih atas tawaran Anda untuk mengedit, namun: 1) Saya tidak cukup akrab dengan CoffeeScript sehingga berisiko mengedit / memecahkan solusi Anda ;-). 2) Menerjemahkan kode Anda ke JS modern harus dianggap penyimpangan dari "maksud asli Jawaban Anda", sehingga tidak boleh melewati Tinjauan 'edit'. Sebaliknya, seseorang dapat memposting Jawaban baru, jika mau, menerjemahkan kode Anda. Idealnya, mereka menghubungkan kembali ke jawaban Anda sebagai inspirasi mereka :-)
SherylHohman
0

Pertanyaan yang bagus, dan jawaban yang bagus dari Benjamin, Kris, et al - terima kasih banyak!

Saya menggunakan ini dalam sebuah proyek dan telah membuat modul berdasarkan kode Benjamin Gruenwald . Ini tersedia di npmjs:

npm i -S promise-spread

Kemudian dalam kode Anda, lakukan

require('promise-spread');

Jika Anda menggunakan perpustakaan seperti any-promise

var Promise = require('any-promise');
require('promise-spread')(Promise);

Mungkin orang lain menganggap ini berguna juga!

AndreasPizsa
sumber
0

Mendefinisikan Penugasan dalam ES6 akan membantu di sini.

let [arg1, arg2] = new Promise((resolve, reject) => {
    resolve([argument1, argument2]);
});
Ravi Teja
sumber
0

Karena fungsi dalam Javascript dapat dipanggil dengan sejumlah argumen, dan dokumen tidak menempatkan batasan apa pun pada onFulfilled()argumen metode selain klausa di bawah ini, saya pikir Anda bisa meneruskan beberapa argumen ke onFulfilled()metode selama nilai janji adalah argumen pertama.

2.2.2.1 itu harus dipanggil setelah janji dipenuhi, dengan nilai janji sebagai argumen pertama.

Jazzepi
sumber
-1

Mengutip artikel di bawah ini, "" lalu "membutuhkan dua argumen, panggilan balik untuk kasus sukses, dan lainnya untuk kasus kegagalan. Keduanya opsional, sehingga Anda dapat menambahkan panggilan balik hanya untuk kasus keberhasilan atau kegagalan."

Saya biasanya melihat halaman ini untuk pertanyaan janji dasar, beri tahu saya jika saya salah

http://www.html5rocks.com/en/tutorials/es6/promises/

Michael Voznesensky
sumber
1
Itu salah, new Promisememiliki sintaks function(resolve, error)sementara thenmemiliki sintaks.then(function(arg) {
megawac
2
@megawac itu sebenarnya benar hanya menempatkan dengan buruk - kemudian menerima dua (kadang-kadang 3) argumen - itu hanya agak jarang
Benjamin Gruenbaum
@BenjaminGruenbaum afaik its.then(function(/*resolve args*/){/*resolve handler*/}, function(/*reject args*/){/*reject handler*/})
megawac
2
Ya, jika Anda membaca dengan seksama, itulah yang diklaim oleh jawaban ini - tidak terlalu berguna dalam konteks pertanyaan ini tetapi tidak salah.
Benjamin Gruenbaum