Bab 4 dari 7 · 30 menit

Pemrograman Asinkron, Event, dan Stream

Penguasaan asynchronous programming mutlak diperlukan agar kamu dapat memanfaatkan arsitektur non-blocking Node.js secara optimal. Pada era awal Node.js, penanganan asinkron mengandalkan fungsi callback dengan konvensi error-first. Dalam konvensi ini, argumen pertama dari callback selalu disediakan untuk menampung objek galat jika terjadi kegagalan.

Namun, penumpukan operasi asinkron berbasis callback yang saling bergantung menghasilkan masalah callback hell atau pyramid of doom, di mana kode menjorok terlalu dalam ke kanan dan penanganan error menjadi repetitif.

Callback dan Callback Hell

Untuk mengatasi hal ini, JavaScript memperkenalkan Promise dan sintaks modern async/await. Objek Promise mewakili nilai di masa depan dengan tiga kondisi: pending, fulfilled, dan rejected. Dengan async/await, kode asinkron dapat ditulis dan dibaca menyerupai kode sinkron dengan memanfaatkan blok try/catch untuk menangkap galat.

// Mengambil data secara asinkron dengan async/await
async function ambilProfil(id) {
  try {
    const user = await ambilUser(id);
    const pesanan = await ambilPesanan(user.id);
    return { user, pesanan };
  } catch (err) {
    console.error('Terjadi kesalahan:', err.message);
    throw err;
  }
}

EventEmitter dan Pola Event-Driven

Node.js dibangun di atas pola event-driven. Fondasi utamanya adalah kelas EventEmitter dari modul events. Objek dapat memancarkan sinyal peristiwa bernama menggunakan metode emit(), dan modul lain dapat menanggapinya dengan mendaftarkan fungsi pendengar melalui metode on() atau once().

const EventEmitter = require('events');
const alurKerja = new EventEmitter();

alurKerja.on('selesai', (data) => {
  console.log('Tugas selesai:', data);
});

alurKerja.emit('selesai', { status: 'sukses' });

Stream dan Buffer

Ketika memproses data berukuran besar seperti file video atau log raksasa, memuat seluruh konten ke memori RAM dapat menyebabkan crash proses. Solusinya adalah menggunakan Stream dan Buffer. Buffer adalah wadah memori biner mentah yang dialokasikan di luar heap V8. Stream memecah aliran data menjadi potongan-potongan buffer kecil dan menyalurkannya dari sumber (Readable) ke tujuan (Writable) menggunakan metode .pipe(). Tipe stream Transform memungkinkan kita memodifikasi potongan data di tengah aliran, misalnya saat melakukan kompresi berkas gzip.

Cek pemahaman

  1. 1. Konvensi standar pemanggilan callback di Node.js menempatkan objek error pada posisi argumen ke berapa?

  2. 2. Apa tujuan utama penggunaan metode .pipe() pada baris kode stream berikut?

    fs.createReadStream('besar.txt')
      .pipe(zlib.createGzip())
      .pipe(fs.createWriteStream('besar.txt.gz'));
  3. 3. Buffer di Node.js mengalokasikan data biner mentah langsung di dalam ruang memori heap mesin V8.