Apa perbedaan antara mengembalikan nilai atau Janji. Menanggapi sejak saat itu ()

314

Apa perbedaan antara:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return "bbb";
  })
  .then(function(result) {
    console.log(result);
  });

dan ini:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return Promise.resolve("bbb");
  })
  .then(function(result) {
    console.log(result);
  });

Saya bertanya karena saya mendapatkan perilaku yang berbeda Menggunakan layanan Angular dan $ http dengan chaining .then (). Sedikit kode terlalu banyak maka pertama contoh di atas.

spirytus
sumber
1
Apa "perilaku berbeda" yang Anda lihat? Kedua contoh harus bekerja dan berperilaku kurang lebih sama. Dalam Promise.resolve()contoh kedua tidak perlu.
JLRishe
4
@pixelbits Tidak ada yang salah dengan mengembalikan janji dari seorang thenpawang, pada kenyataannya, itu adalah aspek kunci dari spesifikasi janji yang dapat Anda lakukan.
Perhatikan bahwa ini berfungsi dengan bersarang sewenang-wenang then- istilah 'bahasa lain' untuk ini adalah thena mapdan a flatMap.
Benjamin Gruenbaum
1
pada baris 2 mengapa Anda harus memanggil res ("aaa"), mengapa tidak dapat mengembalikan "aaa" sudah cukup dan tangkapan Janji untuk diselesaikan () dengan cara yang sama seperti menangkap pengecualian untuk reject ()?
Sam Liddicott
1
@ SamLiddicott memiliki pertanyaan yang sama, sedangkan ranjau sedikit lebih rumit: new Promise((res, rej) => { return fetch('//google.com').then(() => { return "haha"; }) }).then((result) => alert(result));Kode ini hanya akan hang (tidak diselesaikan selamanya). Tapi jika saya mengubah return "haha";ke return res("haha");kemudian itu akan bekerja dan waspada "haha". Bukankah fetch (). Then () sudah membungkus "haha" menjadi janji terselesaikan?
Shaung Cheng

Jawaban:

138

Aturannya adalah, jika fungsi yang ada di thenhandler mengembalikan nilai, janji itu diselesaikan / ditolak dengan nilai itu, dan jika fungsi mengembalikan janji, apa yang terjadi adalah, thenklausa berikutnya adalah thenklausa janji yang dikembalikan fungsi , jadi, dalam hal ini, contoh pertama jatuh melalui urutan normal thensdan mencetak nilai - nilai seperti yang diharapkan, dalam contoh kedua, objek janji yang dikembalikan ketika Anda melakukannya Promise.resolve("bbb")adalah thenyang dipanggil saat rantai (untuk semua maksud dan tujuan). Cara kerjanya sebenarnya dijelaskan di bawah ini secara lebih rinci.

Mengutip dari Janji / spec A +:

Prosedur resolusi janji adalah operasi abstrak yang mengambil sebagai input janji dan nilai, yang kami tunjukkan sebagai [[Resolve]](promise, x). Jika xitu suatu masa lalu, ia berusaha membuat janji mengadopsi keadaanx , dengan asumsi bahwa x berperilaku setidaknya seperti janji . Kalau tidak, itu memenuhi janji dengan nilai x.

Perlakuan ini kemudian memungkinkan implementasi janji untuk beroperasi, selama mereka mengekspos metode Janji / A +-patuh maka. Hal ini juga memungkinkan implementasi Janji / A + untuk "mengasimilasi" implementasi tidak sesuai dengan metode yang masuk akal.

Hal utama yang perlu diperhatikan di sini adalah baris ini:

jika xada janji, adopsi negaranya [3.4]

tautan: https://promisesaplus.com/#point-49

Hrishi
sumber
4
"Adopsi negaranya" adalah cara ringkas dan berguna untuk mengekspresikan perilaku ketika seorang thenpawang mengembalikan janji. +1 untuk referensi spesifikasi.
69
Sebenarnya - bagian yang relevan dari spesifikasi di sini adalah fakta yang [[Resolve]]disebut baik pada thenable dan nilai sehingga pada dasarnya itu membungkus nilai dengan janji sehingga return "aaa"sama dengan return Promise.resolve("aaa")dan return Promise.resolve("aaa")sama dengan return Promise.resolve(Promise.resolve("aaa"))- karena tekad adalah idempoten menyebutnya dengan nilai lebih daripada sekali memiliki hasil yang sama.
Benjamin Gruenbaum
8
@Benjamin Gruenbaum apakah itu berarti kembali "aaa"dan return Promise.resolve("aaa")dapat dipertukarkan dalam thenhal apapun?
CSnerd
9
Ya, itulah artinya.
Benjamin Gruenbaum
118

Secara sederhana, di dalam thenfungsi handler:

A) Kapan xsuatu nilai (angka, string, dll):

  1. return x setara dengan return Promise.resolve(x)
  2. throw x setara dengan return Promise.reject(x)

B) Kapan xJanji yang sudah diselesaikan (tidak tertunda lagi):

  1. return xsetara dengan return Promise.resolve(x), jika Janji sudah terselesaikan.
  2. return xsetara dengan return Promise.reject(x), jika Janji sudah ditolak.

C) Kapan xJanji yang tertunda:

  1. return xakan mengembalikan Janji yang tertunda, dan akan dievaluasi selanjutnya then.

Baca lebih lanjut tentang topik ini di dokumen Promise.prototype.then () .

Arian Acosta
sumber
93

Kedua contoh Anda harus berperilaku sama.

Nilai yang dikembalikan ke dalam then()handler menjadi nilai resolusi dari janji yang dikembalikan dari itu then(). Jika nilai yang dikembalikan ke dalam .then adalah janji, janji yang dikembalikan oleh then()akan "mengadopsi keadaan" dari janji itu dan menyelesaikan / menolak seperti halnya janji yang dikembalikan.

Dalam contoh pertama Anda, Anda kembali "bbb"ke then()penangan pertama , sehingga "bbb"diteruskan ke then()penangan berikutnya .

Dalam contoh kedua, Anda mengembalikan janji yang segera diselesaikan dengan nilai "bbb", sehingga "bbb"diteruskan ke then()penangan berikutnya . (Di Promise.resolve()sini luar).

Hasilnya sama.

Jika Anda dapat menunjukkan kepada kami contoh yang benar-benar menunjukkan perilaku yang berbeda, kami dapat memberi tahu Anda mengapa itu terjadi.

JLRishe
sumber
1
Jawaban bagus! Bagaimana dengan Promise.resolve();vs return;?
FabianTe
2
@ FabianTe Itu juga akan memiliki efek yang sama, kecuali dengan undefinedalih - alih "bbb".
JLRishe
51

Anda sudah mendapat jawaban formal yang bagus. Saya pikir saya harus menambahkan yang pendek.

Hal-hal berikut identik dengan Janji / Janji + :

  • Memanggil Promise.resolve(Dalam kasus Sudut Anda itu $q.when)
  • Memanggil konstruktor janji dan menyelesaikan dalam resolvernya. Dalam kasus Anda itu new $q.
  • Mengembalikan nilai dari thenpanggilan balik.
  • Memanggil Janji. Semua pada array dengan nilai lalu ekstrak nilai itu.

Jadi yang berikut semuanya identik untuk janji atau nilai X:

Promise.resolve(x);
new Promise(function(resolve, reject){ resolve(x); });
Promise.resolve().then(function(){ return x; });
Promise.all([x]).then(function(arr){ return arr[0]; });

Dan tidak mengherankan, spesifikasi janji didasarkan pada Prosedur Resolusi Janji yang memungkinkan interoperasi yang mudah antara perpustakaan (seperti $ q dan janji asli) dan membuat hidup Anda secara keseluruhan lebih mudah. Setiap kali sebuah janji resolusi mungkin terjadi, sebuah resolusi muncul menciptakan keseluruhan konsistensi.

Benjamin Gruenbaum
sumber
bolehkah saya bertanya apa gunanya melakukan Promise.resolve().then(function(){ return x; });? Saya menemukan potongan melakukan sesuatu yang serupa (itu disebut fungsi di dalam thenblok). Saya pikir itu kurang lebih seperti melakukan timeout, tetapi sedikit lebih cepat. jsben.ch/HIfDo
Sampgun
Tidak ada gunanya sama dengan Promise.resolve (x) dalam 99,99% kasus. (0,001% adalah bahwa kita berada di withblok di atas objek atau proxy dengan pengakses xproperti yang melempar pengecualian. Dalam hal itu Promise.resolve (x) akan menyebabkan kesalahan yang dilemparkan tetapi Promise.resolve().then(function(){ return x; });akan menjadi janji yang ditolak karena kesalahan dilemparkan dalam a then).
Benjamin Gruenbaum
Anda menautkan blitz kosong, atau Anda tidak menyimpan. Lagi pula saya tidak berbicara tentang perbedaan di antara pernyataan. Saya berbicara tepat tentang apa yang saya tulis. Hanya untuk menjadi lebih jelas, ini adalah potongan yang saya bicarakan: if (validator) { Promise.resolve().then(() => { this._cdRef.markForCheck(); }); }. Di sini janji tidak diberikan, jadi apa gunanya? Waktu habis akan memiliki (kurang lebih) efek yang sama, atau tidak?
Sampgun
1
Itu melakukan panggilan secara tidak sinkron setelah semua kode sinkron terjadi tetapi sebelum I / O terjadi. Itu disebut "semantik microtick".
Benjamin Gruenbaum
1

Satu-satunya perbedaan adalah bahwa Anda menciptakan janji yang tidak perlu ketika Anda melakukannya return Promise.resolve("bbb"). Mengembalikan janji dari onFulfilled()pawang dimulai dengan resolusi janji . Begitulah cara kerja chaining janji .

vkarpov15
sumber