Bagaimana cara mengakses nilai janji?


146

Saya melihat contoh ini dari dokumen Angular, $qtetapi saya pikir ini mungkin berlaku untuk janji secara umum. Contoh di bawah ini disalin kata demi kata dari dokumen mereka dengan komentar mereka termasuk:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

// promiseB will be resolved immediately after promiseA is resolved and its value
// will be the result of promiseA incremented by 1

Saya tidak jelas bagaimana ini bekerja. Jika saya bisa memanggil .then()hasil yang pertama .then(), merantai mereka, yang saya tahu saya bisa, maka itu promiseBadalah objek janji, tipe Object. Itu bukan Number. Jadi apa yang mereka maksud dengan "nilainya akan menjadi hasil dari janji yang bertambah 1"?

Apakah saya seharusnya mengaksesnya sebagai promiseB.valueatau sesuatu seperti itu? Bagaimana panggilan balik yang berhasil mengembalikan janji DAN mengembalikan "hasil +1"? Saya melewatkan sesuatu.


Saya mengajukan pertanyaan terkait: Mengapa Promise tidak memiliki fungsi get ()?
Roland


Pertanyaan ini berusia 5 tahun dan memiliki jawaban yang diterima ...
temporary_user_name

@tentar_user_name: tidak masalah bagi orang untuk memberikan suara dekat kapan saja, bahkan pada pertanyaan lama.
halfer

Jawaban:


141

promiseA's thenmengembalikan fungsi janji baru ( promiseB) yang segera diselesaikan setelah promiseAteratasi, nilainya adalah nilai dari apa yang dikembalikan dari fungsi sukses dalam promiseA.

Dalam hal promiseAini diselesaikan dengan nilai - resultdan kemudian segera diselesaikan dengan promiseBnilai result + 1.

Mengakses nilai promiseBdilakukan dengan cara yang sama kita mengakses hasil promiseA.

promiseB.then(function(result) {
    // here you can use the result of promiseB
});

Edit Desember 2019 : async/ awaitsekarang standar dalam JS, yang memungkinkan sintaks alternatif untuk pendekatan yang dijelaskan di atas. Anda sekarang dapat menulis:

let result = await functionThatReturnsPromiseA();
result = result + 1;

Sekarang tidak ada janji B, karena kami telah membuka hasil dari janji menggunakan await, dan Anda dapat bekerja secara langsung.

Namun, awaithanya bisa digunakan di dalam suatu asyncfungsi. Jadi untuk memperkecil sedikit, hal di atas harus terkandung seperti:

async function doSomething() {
    let result = await functionThatReturnsPromiseA();
    return result + 1;
}

2
Secara teoritis janji adalah objek mereka sendiri. mereka mengandung hasil yang dapat diakses melalui fungsi keberhasilan janji.
Nachshon Schwartz

2
Jadi jika Anda ingin bekerja dengan nilai balik dari panggilan balik tak sinkron janji, itu harus dilakukan di dalam panggilan balik tak sinkron lainnya. Masuk akal. Saya telah mencari cara untuk mendapatkan beberapa nilai pengembalian primitif utama tetapi saya kira itu akan menentang alasan mengingat konteksnya.
temporary_user_name

2
@Aerovistae sebenarnya, ES6 memperkenalkan generator yang memungkinkan hal ini dan ES7 memperkenalkan fungsi async - keduanya memberikan Anda gula sintaks atas janji yang membuatnya terlihat seperti kode sinkron (dengan menjalankan mesin negara di latar belakang) - jadi tunggu sebentar :)
Benjamin Gruenbaum

25

Ketika sebuah janji diselesaikan / ditolak, itu akan memanggil penangan keberhasilan / kesalahannya:

var promiseB = promiseA.then(function(result) {
   // do something with result
});

The thenMetode juga mengembalikan janji: promiseB, yang akan diselesaikan / ditolak tergantung pada nilai kembali dari handler keberhasilan / error dari promiseA .

Ada tiga nilai yang mungkin bahwa penangan keberhasilan / kesalahan yang dijanjikan dapat kembali yang akan mempengaruhi hasil yang menjanjikan:

1. Return nothing --> PromiseB is resolved immediately, 
   and undefined is passed to the success handler of promiseB
2. Return a value --> PromiseB is resolved immediately,
   and the value is passed to the success handler of promiseB
3. Return a promise --> When resolved, promiseB will be resolved. 
   When rejected, promiseB will be rejected. The value passed to
   the promiseB's then handler will be the result of the promise

Berbekal pemahaman ini, Anda dapat memahami hal-hal berikut:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

Kemudian panggilan mengembalikan janji B segera. Ketika janjiA dipecahkan, itu akan melewati hasilnya untuk penangan sukses janjiA. Karena nilai pengembalian adalah hasil janjiA + 1, penangan keberhasilan mengembalikan nilai (opsi 2 di atas), jadi janjiB akan menyelesaikan segera, dan penangan keberhasilan janjiB akan diteruskan hasil janjiA +1 +.


4

.thenfungsi janjiB menerima apa yang dikembalikan dari .thenfungsi janjiA.

di sini, janji kembali adalah angka, yang akan tersedia sebagai numberparameter dalam fungsi keberhasilan janji. yang kemudian akan bertambah 1


3

Memilah komentar sedikit berbeda dari pengertian Anda saat ini mungkin membantu:

// promiseB will be resolved immediately after promiseA is resolved

Ini menyatakan bahwa itu promiseBadalah janji tetapi akan diselesaikan segera setelah promiseAdiselesaikan. Cara lain untuk melihat ini berarti promiseA.then()mengembalikan janji yang ditugaskan promiseB.

// and its value will be the result of promiseA incremented by 1

Ini berarti bahwa nilai yang promiseAdiselesaikan adalah nilai yang promiseBakan menerima sebagai nilai successCallback-nya:

promiseB.then(function (val) {
  // val is now promiseA's result + 1
});

2

jawaban pixelbits benar dan Anda harus selalu menggunakan .then()untuk mengakses nilai janji dalam kode produksi.

Namun, ada cara untuk mengakses nilai janji secara langsung setelah diselesaikan dengan menggunakan simpul.js internal yang tidak didukung berikut ini:

process.binding('util').getPromiseDetails(myPromise)[1]

PERINGATAN: process.binding tidak pernah dimaksudkan untuk digunakan di luar inti nodejs dan tim inti nodejs secara aktif mencari untuk menghentikannya

https://github.com/nodejs/node/pull/22004 https://github.com/nodejs/node/issues/22064


1

Contoh ini saya temukan cukup jelas. Perhatikan bagaimana menunggu menunggu hasilnya dan Anda kehilangan Janji yang dikembalikan.

cryA = crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
Promise {<pending>}
cryB = await crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
{publicKey: CryptoKey, privateKey: CryptoKey}

Ini harus dalam fungsi async.
Samed

0
promiseA(pram).then(
     result => { 
     //make sure promiseA function allready success and response
     //do something here
}).catch(err => console.log(err)) => {
     // handle error with try catch
}

1
Sementara kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang bagaimana dan mengapa memecahkan masalah akan meningkatkan nilai jangka panjang jawaban.
Alexander

0

Anda dapat dengan mudah melakukannya menggunakan metode tunggu async dalam javascript.

Di bawah ini adalah contoh mengambil nilai janji WebRTC menggunakan batas waktu.

function await_getipv4(timeout = 1000) {
    var t1 = new Date();
    while(!window.ipv4) {
        var stop = new Date() - t1 >= timeout;
        if(stop) {
            console.error('timeout exceeded for await_getipv4.');
            return false;
        }
    }
    return window.ipv4;
}

function async_getipv4() {
    var ipv4 = null;
    var findIP = new Promise(r=>{var w=window,a=new (w.RTCPeerConnection||w.mozRTCPeerConnection||w.webkitRTCPeerConnection)({iceServers:[]}),b=()=>{};a.createDataChannel("");a.createOffer(c=>a.setLocalDescription(c,b,b),b);a.onicecandidate=c=>{try{c.candidate.candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g).forEach(r)}catch(e){}}})
    findIP.then(ip => window.ipv4 = ip);
    return await_getipv4();
};


Sangat penting untuk menjalankan cuplikan ini bukan di sini tetapi di peramban yang sebenarnya, saya yakin ini karena sandboxing.
OxFEEDFACE

0

Di Node REPL, untuk mendapatkan koneksi DB yang merupakan nilai janji, saya mengambil pendekatan berikut:

let connection
try {
  (async () => {
    connection = await returnsAPromiseResolvingToConnection()
  })()
} catch(err) {
  console.log(err)
}

Garis dengan awaitbiasanya akan mengembalikan janji. Kode ini dapat disisipkan ke dalam Node REPL atau jika disimpan di index.jsdalamnya dapat dijalankan di Bash dengan

node -i -e "$(< index.js)"

yang membuat Anda di Node REPL setelah menjalankan skrip dengan akses ke variabel yang ditetapkan. Untuk mengonfirmasi bahwa fungsi asinkron telah kembali, Anda dapat login connectionmisalnya, dan kemudian Anda siap untuk menggunakan variabel. Salah satu tentu saja tidak ingin mengandalkan fungsi asinkron yang sedang diselesaikan untuk kode apa pun dalam skrip di luar fungsi asinkron.


0

Ada beberapa jawaban yang baik di atas dan di sini adalah versi fungsi ES6 Arrow

var something = async() => {
   let result = await functionThatReturnsPromiseA();
   return result + 1;
}

0

Saya seorang pembelajar lambat javascript janji, secara default semua fungsi async mengembalikan janji, Anda dapat membungkus hasil Anda sebagai:

(async () => {
//Optional "await"
  await yourAsyncFunctionOrPromise()
    .then(function (result) {
      return result +1;
    })
    .catch(function (error) {
      return error;
    })()
})

" Ekspresi menunggu menyebabkan eksekusi fungsi async untuk berhenti sampai Janji diselesaikan (yaitu, dipenuhi atau ditolak), dan untuk melanjutkan eksekusi fungsi async setelah pemenuhan. Ketika dilanjutkan, nilai dari ekspresi menunggu adalah nilai dari Janji yang dipenuhi. Jika Janji ditolak, ekspresi tunggu melempar nilai yang ditolak ."

Baca lebih lanjut tentang menunggu dan berjanji di MDN Web Documents


-5

Mungkin contoh kode skrip kecil ini akan membantu.

private getAccount(id: Id) : Account {
    let account = Account.empty();
    this.repository.get(id)
        .then(res => account = res)
        .catch(e => Notices.results(e));
    return account;
}

Di sini repository.get(id)pengembaliannya a Promise<Account>. Saya menetapkannya ke variabel accountdalam thenpernyataan.


1
Kode Anda mengembalikan akun sebelum janji dapat diselesaikan dan inilah mengapa itu tidak dipilih, kode Anda selalu mengembalikan Account.empty ();
Felype
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.