Cara kerja Node.js
Unit ini menjelaskan bagaimana Node.js menangani tugas masuk ke runtime JavaScript.
Jenis tugas
Aplikasi JavaScript memiliki dua jenis tugas:
- Tugas sinkron: Tugas-tugas ini terjadi secara berurutan. Sumber daya tidak bergantung pada sumber daya lain untuk diselesaikan. Contohnya adalah operasi matematika atau manipulasi string.
- Asinkron: Tugas-tugas ini mungkin tidak segera diselesaikan karena bergantung pada sumber daya lain. Contohnya adalah permintaan jaringan atau operasi sistem file.
Karena Anda ingin program Anda berjalan secepat mungkin, Anda ingin mesin JavaScript dapat terus bekerja saat menunggu respons dari operasi asinkron. Untuk melakukannya, ia menambahkan tugas asinkron ke antrean tugas dan terus mengerjakan tugas berikutnya.
Mengelola antrean tugas dengan perulangan peristiwa
Node.js menggunakan arsitektur berbasis peristiwa mesin JavaScript untuk memproses permintaan asinkron. Diagram berikut menggambarkan cara kerja perulangan peristiwa V8, pada tingkat tinggi:
Tugas asinkron, ditandai dengan sintaks yang sesuai (ditunjukkan di bawah), ditambahkan ke perulangan peristiwa. Tugas ini mencakup pekerjaan yang akan dilakukan dan fungsi panggilan balik untuk menerima hasilnya. Ketika operasi intensif selesai, fungsi panggilan balik dipicu dengan hasilnya.
Operasi sinkron versus operasi asinkron
API Node.js menyediakan operasi asinkron dan sinkron untuk beberapa operasi yang sama seperti operasi file. Meskipun umumnya Anda harus selalu berpikir asinkron-terlebih dahulu, ada kalanya Anda mungkin menggunakan operasi sinkron.
Contohnya adalah ketika antarmuka baris perintah (CLI) membaca file dan kemudian segera menggunakan data dalam file. Dalam hal ini, Anda dapat menggunakan versi sinkron dari operasi file karena tidak ada sistem atau orang lain yang menunggu untuk menggunakan aplikasi.
Namun, jika Anda membangun server web, Anda harus selalu menggunakan versi asinkron dari operasi file untuk tidak memblokir kemampuan eksekusi utas tunggal untuk memproses permintaan pengguna lain.
Dalam pekerjaan Anda sebagai pengembang di TailWind Traders, Anda harus memahami perbedaan antara operasi sinkron dan asinkron dan kapan menggunakan masing-masing operasi.
Performa melalui operasi asinkron
Node.js memanfaatkan sifat unik javaScript berbasis peristiwa yang membuat tugas server penulisan cepat dan berkinerja tinggi. JavaScript, ketika digunakan dengan benar dengan teknik asinkron, dapat menghasilkan hasil performa yang sama dengan bahasa tingkat rendah seperti C karena peningkatan performa yang dimungkinkan oleh mesin V8.
Teknik asinkron hadir dalam 3 gaya, yang perlu Anda kenali dalam pekerjaan Anda:
- Asinkron/tunggu (disarankan): Teknik asinkron terbaru yang menggunakan
async
kata kunci danawait
untuk menerima hasil operasi asinkron. Asinkron/tunggu digunakan di banyak bahasa pemrograman. Umumnya, proyek baru dengan dependensi yang lebih baru akan menggunakan gaya kode asinkron ini. - Panggilan balik: Teknik asinkron asli yang menggunakan fungsi panggilan balik untuk menerima hasil operasi asinkron. Anda akan melihat ini di basis kode yang lebih lama dan di API Node.js yang lebih lama.
- Promises: Teknik asinkron yang lebih baru yang menggunakan objek janji untuk menerima hasil operasi asinkron. Anda akan melihat ini di basis kode yang lebih baru dan di API Node.js yang lebih baru. Anda mungkin harus menulis kode berbasis janji dalam pekerjaan Anda untuk membungkus API lama yang tidak akan diperbarui. Dengan menggunakan janji untuk pembungkusan ini, Anda mengizinkan kode untuk digunakan dalam berbagai proyek versi Node.js yang lebih besar daripada dalam gaya asinkron/menunggu kode yang lebih baru.
Asinkron/menunggu
Asinkron/menunggu adalah cara terbaru untuk menangani pemrograman asinkron. Asinkron/menunggu adalah gula sintaktik di atas janji dan membuat kode asinkron terlihat lebih seperti kode sinkron. Lebih mudah juga dibaca dan dirawat.
Contoh yang sama menggunakan asinkron/menunggu terlihat seperti ini:
// async/await asynchronous example
const fs = require('fs').promises;
const filePath = './file.txt';
// `async` before the parent function
async function readFileAsync() {
try {
// `await` before the async method
const data = await fs.readFile(filePath, 'utf-8');
console.log(data);
console.log('Done!');
} catch (error) {
console.log('An error occurred...: ', error);
}
}
readFileAsync()
.then(() => {
console.log('Success!');
})
.catch((error) => {
console.log('An error occurred...: ', error);
});
Ketika asinkron/menunggu dirilis pada ES2017, kata kunci hanya dapat digunakan dalam fungsi dengan fungsi tingkat atas menjadi janji. Meskipun janji tidak harus memiliki then
bagian dan catch
, masih diharuskan untuk memiliki promise
sintaks untuk dijalankan.
Fungsi async
selalu mengembalikan janji, bahkan jika tidak memiliki await
panggilan di dalamnya. Janji akan diselesaikan dengan nilai yang dikembalikan oleh fungsi . Jika fungsi melemparkan kesalahan, janji akan ditolak dengan nilai yang dilemparkan.
Promises
Karena panggilan balik berlapis bisa sulit dibaca dan dikelola, Node.js menambahkan dukungan untuk janji. Janji adalah objek yang mewakili penyelesaian akhir (atau kegagalan) dari operasi asinkron.
Fungsi promise memiliki format:
// Create a basic promise function
function promiseFunction() {
return new Promise((resolve, reject) => {
// do something
if (error) {
// indicate success
reject(error);
} else {
// indicate error
resolve(data);
}
});
}
// Call a basic promise function
promiseFunction()
.then((data) => {
// handle success
})
.catch((error) => {
// handle error
});
Metode then
ini dipanggil ketika janji dipenuhi dan metode dipanggil catch
ketika janji ditolak.
Untuk membaca file secara asinkron dengan janji, kodenya adalah:
// promises asynchronous example
const fs = require('fs').promises;
const filePath = './file.txt';
// request to read a file
fs.readFile(filePath, 'utf-8')
.then((data) => {
console.log(data);
console.log('Done!');
})
.catch((error) => {
console.log('An error occurred...: ', error);
});
console.log(`I'm the last line of the file!`);
Asinkron/tunggu tingkat atas
Versi terbaru Node.js menambahkan asinkron/tunggu tingkat atas untuk modul ES6. Anda perlu menambahkan properti bernama type
di package.json dengan nilai module
untuk menggunakan fitur ini.
{
"type": "module"
}
Kemudian Anda dapat menggunakan await
kata kunci di tingkat atas kode Anda
// top-level async/await asynchronous example
const fs = require('fs').promises;
const filePath = './file.txt';
// `async` before the parent function
try {
// `await` before the async method
const data = await fs.readFile(filePath, 'utf-8');
console.log(data);
console.log('Done!');
} catch (error) {
console.log('An error occurred...: ', error);
}
console.log("I'm the last line of the file!");
Panggilan balik
Ketika Node.js awalnya dirilis, pemrograman asinkron ditangani dengan menggunakan fungsi panggilan balik. Panggilan balik adalah fungsi yang diteruskan sebagai argumen ke fungsi lain. Ketika tugas selesai, fungsi panggilan balik dipanggil.
Urutan parameter fungsi penting. Fungsi panggilan balik adalah parameter terakhir dari fungsi.
// Callback function is the last parameter
function(param1, param2, paramN, callback)
Nama fungsi dalam kode yang Anda pertahankan mungkin tidak disebut callback
. Ini bisa dipanggil cb
atau atau done
next
. Nama fungsi tidak penting, tetapi urutan parameter penting.
Perhatikan tidak ada indikasi sindikasi bahwa fungsinya asinkron. Anda harus tahu bahwa fungsi ini asinkron dengan membaca dokumentasi atau terus membaca kode.
Contoh panggilan balik dengan fungsi panggilan balik bernama
Kode berikut memisahkan fungsi asinkron dari panggilan balik. Ini mudah dibaca dan dipahami dan memungkinkan Anda menggunakan kembali panggilan balik untuk fungsi asinkron lainnya.
// callback asynchronous example
// file system module from Node.js
const fs = require('fs');
// relative path to file
const filePath = './file.txt';
// callback
const callback = (error, data) => {
if (error) {
console.log('An error occurred...: ', error);
} else {
console.log(data); // Hi, developers!
console.log('Done!');
}
};
// async request to read a file
//
// parameter 1: filePath
// parameter 2: encoding of utf-8
// parmeter 3: callback function
fs.readFile(filePath, 'utf-8', callback);
console.log("I'm the last line of the file!");
Hasil yang benar adalah:
I'm the last line of the file!
Hi, developers!
Done!
Pertama, fungsi fs.readFile
asinkron dimulai dan masuk ke perulangan peristiwa. Kemudian, eksekusi kode berlanjut ke baris kode berikutnya, yang merupakan yang terakhir console.log
. Setelah file dibaca, fungsi panggilan balik dipanggil dan dua pernyataan console.log dijalankan.
Contoh panggilan balik dengan fungsi anonim
Contoh berikut menggunakan fungsi panggilan balik anonim, yang berarti fungsi tidak memiliki nama dan tidak dapat digunakan kembali oleh fungsi anonim lainnya.
// callback asynchronous example
// file system module from Node.js
const fs = require('fs');
// relative path to file
const filePath = './file.txt';
// async request to read a file
//
// parameter 1: filePath
// parameter 2: encoding of utf-8
// parmeter 3: callback function () => {}
fs.readFile(filePath, 'utf-8', (error, data) => {
if (error) {
console.log('An error occurred...: ', error);
} else {
console.log(data); // Hi, developers!
console.log('Done!');
}
});
console.log("I'm the last line of the file!");
Hasil yang benar adalah:
I'm the last line of the file!
Hi, developers!
Done!
Ketika kode dijalankan, fungsi fs.readFile
asinkron dimulai dan masuk ke perulangan peristiwa. Selanjutnya eksekusi berlanjut ke baris kode berikut, yang merupakan yang terakhir console.log
. Ketika file dibaca, fungsi panggilan balik dipanggil dan dua pernyataan console.log dijalankan.
Panggilan balik berlapis
Karena Anda mungkin perlu memanggil panggilan balik asinkron berikutnya dan kemudian yang lain, kode panggilan balik mungkin menjadi berlapis. Ini disebut callback hell dan sulit dibaca dan dipertahankan.
// nested callback example
// file system module from Node.js
const fs = require('fs');
fs.readFile(param1, param2, (error, data) => {
if (!error) {
fs.writeFile(paramsWrite, (error, data) => {
if (!error) {
fs.readFile(paramsRead, (error, data) => {
if (!error) {
// do something
}
});
}
});
}
});
API Sinkron
Node.js juga memiliki sekumpulan API sinkron. API ini memblokir eksekusi program hingga tugas selesai. API sinkron berguna saat Anda ingin membaca file lalu segera menggunakan data dalam file.
Fungsi sinkron (pemblokiran) di Node.js menggunakan konvensi penamaan functionSync
. Misalnya, API asinkron readFile
memiliki mitra sinkron bernama readFileSync
. Penting untuk menegakkan standar ini dalam proyek Anda sendiri sehingga kode Anda mudah dibaca dan dipahami.
// synchronous example
const fs = require('fs');
const filePath = './file.txt';
try {
// request to read a file
const data = fs.readFileSync(filePath, 'utf-8');
console.log(data);
console.log('Done!');
} catch (error) {
console.log('An error occurred...: ', error);
}
Sebagai pengembang baru di TailWind Traders, Anda mungkin diminta untuk memodifikasi semua jenis kode Node.js. Penting untuk memahami perbedaan antara API sinkron dan asinkron, dan sintaks yang berbeda untuk kode asinkron.