Ada perbedaan kecil namun agak penting antara fungsi yang hanya mengembalikan janji dan fungsi yang dinyatakan menggunakan
async
.
Lihatlah potongan kode berikut:
function fn(obj) { const someProp = obj.someProp return Promise.resolve(someProp) } async function asyncFn(obj) { const someProp = obj.someProp return Promise.resolve(someProp) } asyncFn().catch(err => console.error('Catched'))
Seperti yang Anda lihat, kedua fungsi memiliki badan yang sama di mana kami mencoba mengakses properti argumen yang tidak didefinisikan dalam kedua kasus. Satu-satunya perbedaan antara kedua fungsi adalah
asyncFn
dideklarasikan menggunakan
async
.
Ini berarti bahwa JavaScript memastikan bahwa fungsi
asnycFn
mengembalikan janji (berhasil atau gagal), bahkan jika kesalahan terjadi di dalamnya, dalam kasus kami, blok
.catch()
akan menangkapnya.
Namun, dalam kasus fungsi
fn
, mesin masih tidak tahu bahwa fungsi akan mengembalikan janji, dan oleh karena itu kode tidak akan mencapai blok
.catch()
, kesalahan tidak akan tertangkap dan akan jatuh ke konsol.
Lebih banyak contoh hidup
Saya tahu apa yang Anda pikirkan sekarang:
"Kapan aku akan membuat kesalahan seperti itu?"
Tertebak?
Baiklah, mari kita buat aplikasi sederhana yang melakukan hal itu.
Misalkan kita memiliki aplikasi yang dibangun menggunakan Express dan MongoDB yang menggunakan driver MongoDB Node.JS. Jika Anda tidak mempercayai saya, saya telah menempatkan semua kode sumber di
repositori Github ini , sehingga Anda dapat mengkloningnya dan menjalankannya secara lokal, tetapi saya juga akan menggandakan semua kode di sini.
Ini file
app.js
kami:
Lihatlah dengan cermat pada blok
.catch()
! Di sinilah keajaiban tidak akan terjadi.
File
db.js
digunakan untuk terhubung ke database mongo:
'use strict' const MongoClient = require('mongodb').MongoClient const url = 'mongodb://localhost:27017' const dbName = 'async-promise-test' const client = new MongoClient(url) let db module.exports = { connect() { return new Promise((resolve, reject) => { client.connect(err => { if (err) return reject(err) console.log('Connected successfully to server') db = client.db(dbName) resolve(db) }) }) }, getDb() { return db } }
Dan akhirnya, kami memiliki file
user-model.js
di mana hanya satu fungsi
getUserById
yang saat ini didefinisikan:
Jika Anda melihat file
app.js
, Anda akan melihat bahwa ketika kita pergi ke
localhost:3000/users/<id>
kita memanggil fungsi
getUserById
didefinisikan dalam file
user-model.js
, melewati parameter
id
sebagai permintaan.
Katakanlah Anda pergi ke alamat berikut:
localhost:3000/users/1
. Menurut Anda apa yang akan terjadi selanjutnya?
Nah, jika Anda menjawab: "Saya akan melihat kesalahan besar dari MongoClient" - Anda benar. Untuk lebih tepatnya, Anda akan melihat kesalahan berikut:
Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters
.
Dan menurut Anda apakah blok
.catch()
akan dipanggil dalam cuplikan kode berikutnya?
Tidak. Dia tidak akan dipanggil.
Dan apa yang terjadi jika Anda mengubah deklarasi fungsi untuk ini?
module.exports = {
Ya, Anda mulai mengerti apa itu.
.catch()
akan dipanggil, dan kami akan dapat memproses kesalahan yang tertangkap dan menunjukkannya kepada pengguna.
Alih-alih sebuah kesimpulan
Saya harap informasi ini bermanfaat bagi sebagian dari Anda. Harap perhatikan bahwa artikel ini tidak mencoba memaksa Anda untuk selalu menggunakan fungsi asinkron - meskipun sangat keren. Mereka memiliki kasus penggunaan sendiri, tetapi mereka masih sintaksis atas janji.
Saya hanya ingin Anda tahu bahwa kadang-kadang janji bisa membuat perbedaan besar, dan ketika (ya, bukan "jika") Anda menemukan kesalahan yang dibahas dalam artikel ini, Anda akan tahu alasan yang mungkin untuk terjadinya.
Catatan PS perev.: ke artikel asli, komentar yang berguna ditinggalkan dari pengguna Craig P Hicks, yang (setelah komentar di komentar) saya memutuskan untuk mengutip di sini:Saya ingin menarik perhatian pada satu detail, (di lingkungan pengembangan saya) kesalahan yang terjadi di tubuh Promise.resolve({<body>})
tidak "tertangkap":
Promise.resolve((()=>{throw "oops"; })()) .catch(e=>console("Catched ",e));
tetapi kesalahan yang terjadi di tubuh new Promise()
( sekitar terjemahan: dalam "Janji yang tepat" yang asli ) adalah "tertangkap":
(new Promise((resolve,reject)=>{ resolve((()=>{throw "oops"})()) })) .catch(e=>console.log("Catched ",e));
Bagaimana dengan pernyataan ini:
async function fn() { <body> }
semantik, opsi ini setara dengan ini:
function fn() { return new Promise((resolve,reject)=>{ resolve({ <body> }) }) }
Karenanya, fragmen kode di bawah ini akan menemukan kesalahan jika <body> memiliki new Promise()
( sekitar Terjemahan: dalam "Janji yang tepat" ):
function fn() { return Promise.resolve({<body}); }
Jadi, agar contoh dari awal artikel untuk "menangkap" kesalahan dalam kedua kasus, perlu untuk mengembalikan bukan Promise.resolve()
, tetapi new Promise()
dalam fungsi: function fn(obj) { return new Promise((resolve, reject) => { const someProp = obj.someProp; resolve(someProp); }); } async function asyncFn(obj) { return new Promise((resolve, reject) => { const someProp = obj.someProp; resolve(someProp); }); } asyncFn().catch(err => console.error("Catched"));