Kapan saya harus menggunakan pemrograman berbasis acara?

65

Saya telah melewati panggilan balik atau hanya memicu fungsi dari fungsi lain dalam program saya untuk membuat sesuatu terjadi setelah tugas selesai. Ketika sesuatu selesai, saya langsung memicu fungsi:

var ground = 'clean';

function shovelSnow(){
    console.log("Cleaning Snow");
    ground = 'clean';
}

function makeItSnow(){
    console.log("It's snowing");
    ground = 'snowy';
    shovelSnow();
}

Tapi saya sudah membaca tentang berbagai strategi dalam pemrograman, dan yang saya pahami kuat, tetapi belum dipraktikkan, berbasis event (saya pikir metode yang saya baca disebut "pub-sub" ):

var ground = 'clean';

function shovelSnow(){
    console.log("Cleaning Snow");
    ground = 'clean';
}

function makeItSnow(){
    console.log("It's snowing");
    ground = 'snowy';
    $(document).trigger('snow');
}

$(document).bind('snow', shovelSnow);

Saya ingin memahami kekuatan dan kelemahan obyektif pemrograman berbasis acara, vs hanya memanggil semua fungsi Anda dari dalam fungsi lain. Dalam situasi pemrograman manakah pemrograman berbasis peristiwa masuk akal untuk digunakan?

Viziionary
sumber
2
Sebagai tambahan, Anda bisa menggunakannya $(document).bind('snow', shovelShow). Tidak perlu membungkusnya dalam fungsi anonim.
Karl Bielefeldt
4
Anda mungkin juga tertarik untuk belajar tentang "pemrograman reaktif", yang memiliki banyak kesamaan dengan pemrograman berbasis acara.
Eric Lippert

Jawaban:

75

Suatu acara adalah pemberitahuan yang menggambarkan kejadian dari masa lalu baru-baru ini.

Implementasi tipikal dari sistem yang digerakkan oleh event menggunakan fungsi dispatcher dan fungsi handler (atau pelanggan ). Dispatcher menyediakan API untuk mengirim penangan ke acara (jQuery's bind), dan metode untuk mempublikasikan acara kepada pelanggannya ( triggerdi jQuery). Saat Anda berbicara tentang acara IO atau UI, biasanya juga ada loop acara , yang mendeteksi acara baru seperti klik mouse dan meneruskannya ke operator. Di JS-land, dispatcher dan loop acara disediakan oleh browser.

Untuk kode yang berinteraksi langsung dengan pengguna - merespons penekanan tombol dan klik - pemrograman berdasarkan peristiwa (atau variasi daripadanya, seperti pemrograman reaktif fungsional ) hampir tidak dapat dihindari. Anda, sang programmer, tidak tahu kapan atau di mana pengguna akan mengklik, jadi tergantung pada kerangka kerja GUI atau browser untuk mendeteksi tindakan pengguna di loop acara dan memberi tahu kode Anda. Jenis infrastruktur ini juga digunakan dalam aplikasi jaringan (cf NodeJS).

Contoh Anda, di mana Anda meningkatkan suatu peristiwa dalam kode Anda daripada memanggil fungsi secara langsung memiliki beberapa tradeoff yang lebih menarik, yang akan saya bahas di bawah ini. Perbedaan utama adalah bahwa penerbit acara ( makeItSnow) tidak menentukan penerima panggilan; yang terhubung di tempat lain (dalam panggilan ke binddalam contoh Anda). Ini disebut api-dan-lupakan : makeItSnowmengumumkan kepada dunia bahwa salju turun, tetapi tidak peduli siapa yang mendengarkan, apa yang terjadi selanjutnya, atau ketika itu terjadi - ia hanya menyiarkan pesan dan membersihkan debu dari tangannya.


Jadi pendekatan event-driven decouples pengirim pesan dari penerima. Satu keuntungan yang bisa Anda dapatkan dari ini adalah bahwa suatu peristiwa tertentu mungkin memiliki banyak penangan. Anda dapat mengikat gritRoadsfungsi ke acara salju Anda tanpa mempengaruhi shovelSnowpenangan yang ada . Anda memiliki fleksibilitas dalam cara aplikasi Anda terhubung; untuk mematikan perilaku Anda hanya perlu menghapus bindpanggilan daripada pergi mencari kode untuk menemukan semua contoh perilaku.

Keuntungan lain dari pemrograman berbasis acara adalah memberi Anda tempat untuk menaruh keprihatinan yang saling terkait. Dispatcher peristiwa memainkan peran Mediator , dan beberapa perpustakaan (seperti Brighter ) menggunakan pipa sehingga Anda dapat dengan mudah memasang persyaratan umum seperti logging atau kualitas layanan.

Pengungkapan penuh: Brighter dikembangkan di Huddle, tempat saya bekerja.

Keuntungan ketiga dari memisahkan pengirim dari suatu peristiwa dari penerima adalah memberi Anda keleluasaan ketika Anda menangani acara tersebut. Anda dapat memproses setiap jenis acara dengan utasnya sendiri (jika pengirim acara Anda mendukungnya), atau Anda dapat menempatkan acara yang ditinggikan ke pialang pesan seperti RabbitMQ dan menanganinya dengan proses asinkron atau bahkan memprosesnya dalam semalam massal. Penerima acara dapat dalam proses yang terpisah atau pada mesin yang terpisah. Anda tidak perlu mengubah kode yang memunculkan acara untuk melakukan ini! Ini adalah Ide Besar di balik arsitektur "layanan mikro": layanan otonom berkomunikasi menggunakan acara, dengan pesan middleware sebagai tulang punggung aplikasi.

Untuk contoh yang agak berbeda dari gaya yang digerakkan oleh peristiwa, lihat desain yang digerakkan oleh domain, tempat acara domain digunakan untuk membantu memisahkan agregat. Misalnya, pertimbangkan toko online yang merekomendasikan produk berdasarkan riwayat pembelian Anda. A Customerperlu memiliki riwayat pembelian yang diperbarui ketika a ShoppingCartdibayar. The ShoppingCartagregat mungkin memberitahu Customerdengan mengangkat CheckoutCompletedacara; itu Customerakan diperbarui dalam transaksi terpisah dalam menanggapi acara tersebut.


Kelemahan utama dari model yang digerakkan oleh peristiwa ini adalah tipuan. Sekarang lebih sulit untuk menemukan kode yang menangani acara tersebut karena Anda tidak bisa menavigasi saja menggunakan IDE Anda; Anda harus mencari tahu di mana acara tersebut terikat dalam konfigurasi dan berharap bahwa Anda telah menemukan semua penangan. Masih ada banyak hal yang perlu diingat di suatu waktu. Konvensi gaya kode dapat membantu di sini (misalnya, meletakkan semua panggilan ke binddalam satu file). Demi kewarasan Anda, penting untuk hanya menggunakan satu pengirim acara dan menggunakannya secara konsisten.

Kerugian lain adalah sulit untuk memperbaiki acara. Jika Anda perlu mengubah format acara Anda juga harus mengubah semua penerima. Ini diperburuk ketika pelanggan suatu acara menggunakan mesin yang berbeda, karena sekarang Anda perlu menyinkronkan rilis perangkat lunak!

Dalam keadaan tertentu, kinerja dapat menjadi perhatian. Saat memproses pesan, operator harus:

  1. Cari penangan yang benar dalam beberapa struktur data.
  2. Buat saluran pemroses pesan untuk setiap penangan. Ini mungkin melibatkan banyak alokasi memori.
  3. Hubungi penangan secara dinamis (mungkin menggunakan refleksi jika bahasa membutuhkannya).

Ini tentu saja lebih lambat daripada pemanggilan fungsi biasa, yang hanya melibatkan mendorong bingkai baru pada stack. Namun, fleksibilitas yang diberikan arsitektur event-driven membuat Anda lebih mudah untuk mengisolasi dan mengoptimalkan kode lambat. Memiliki kemampuan untuk mengirimkan pekerjaan ke prosesor asinkron adalah kemenangan besar di sini, karena memungkinkan Anda untuk melayani permintaan segera sementara kerja keras ditangani di latar belakang. Bagaimanapun, jika Anda berinteraksi dengan DB atau menggambar hal-hal di layar maka biaya IO benar-benar akan membebani biaya pemrosesan pesan. Ini adalah kasus menghindari optimasi prematur.


Singkatnya, acara adalah cara yang bagus untuk membangun perangkat lunak yang digabungkan secara longgar, tetapi bukan tanpa biaya. Ini akan menjadi kesalahan, misalnya, untuk mengganti setiap panggilan fungsi dalam aplikasi Anda dengan suatu peristiwa. Gunakan acara untuk membuat divisi arsitektur yang bermakna.

Benjamin Hodgson
sumber
2
Jawaban ini sama dengan jawaban 5377 yang saya pilih benar; Saya mengubah pilihan saya untuk menandai yang ini karena ini menguraikan lebih jauh.
Viziionary
1
Apakah kecepatan merupakan kerugian signifikan dari kode yang digerakkan oleh peristiwa? Sepertinya bisa, tapi saya tidak tahu.
raptortech97
1
@ raptortech97 tentu saja bisa. Untuk kode yang perlu sangat cepat, Anda mungkin ingin menghindari mengirimkan peristiwa dalam loop batin; untungnya, dalam situasi seperti itu biasanya ditentukan dengan baik apa yang perlu Anda lakukan, sehingga Anda tidak perlu ekstra fleksibel acara (atau mempublikasikan / berlangganan atau pengamat, yang merupakan mekanisme setara dengan terminologi yang berbeda).
Jules
1
Perhatikan juga bahwa ada beberapa bahasa (misalnya Erlang) yang dibangun di sekitar model aktor di mana semuanya adalah pesan (acara). Dalam hal ini kompiler dapat memutuskan apakah akan mengimplementasikan pesan / acara sebagai panggilan fungsi langsung atau sebagai komunikasi.
Brendan
1
Untuk "kinerja", saya pikir kita perlu membedakan antara kinerja single-threaded dan skalabilitas. Pesan / acara dapat menjadi lebih buruk untuk kinerja single-threaded (tetapi dapat dikonversi menjadi panggilan fungsi dengan biaya tambahan nol dan tidak lebih buruk), dan untuk skalabilitas lebih unggul dalam segala hal (mis. Kemungkinan akan menghasilkan peningkatan kinerja besar-besaran pada multi modern -CPU dan sistem "banyak-CPU" di masa depan).
Brendan
25

Pemrograman berbasis peristiwa digunakan ketika program tidak mengontrol urutan peristiwa yang dilakukan. Alih-alih, aliran program diarahkan oleh proses luar seperti pengguna (misalnya GUI), sistem lain (misalnya klien / server), atau proses lain (misalnya RPC).

Sebagai contoh, skrip pemrosesan batch tahu apa yang perlu dilakukan sehingga hanya melakukannya. Itu bukan berbasis acara.

Pengolah kata duduk di sana dan menunggu pengguna untuk mulai mengetik. Tekan tombol adalah peristiwa yang memicu fungsionalitas untuk memperbarui buffer dokumen internal. Program tidak dapat mengetahui apa yang ingin Anda ketikkan, sehingga harus didorong oleh peristiwa.

Sebagian besar program GUI dikendalikan oleh peristiwa karena dibuat berdasarkan interaksi pengguna. Namun, program berbasis acara tidak terbatas pada GUI, yang merupakan contoh paling umum bagi kebanyakan orang. Server web menunggu klien untuk terhubung dan mengikuti idiom serupa. Proses latar belakang pada komputer Anda juga dapat merespons acara. Misalnya, pemindai virus berdasarkan permintaan dapat menerima peristiwa dari OS terkait file yang baru dibuat atau diperbarui, kemudian memindai file tersebut dari virus.


sumber
18

Dalam aplikasi berbasis acara, konsep Pendengar Acara akan memberi Anda kemampuan untuk menulis aplikasi yang lebih longgar .

Misalnya modul pihak ketiga atau plug-in dapat menghapus catatan dari database dan kemudian memicu receordDeletedacara dan menyerahkan sisanya ke pendengar acara untuk melakukan pekerjaan mereka. Semuanya akan berfungsi dengan baik, meskipun modul pemicunya bahkan tidak tahu siapa yang mendengarkan acara khusus ini atau apa yang akan terjadi selanjutnya.

53777A
sumber
6

Sebuah analogi sederhana yang ingin saya tambahkan yang membantu saya:

Pikirkan komponen (atau objek) aplikasi Anda sebagai grup besar teman-teman Facebook.

Ketika salah satu teman Anda ingin memberi tahu Anda sesuatu, mereka dapat menghubungi Anda secara langsung atau mempostingnya ke dinding Facebook mereka. Ketika mereka mempostingnya ke Facebook mereka, maka siapa pun dapat melihatnya dan bereaksi terhadapnya, tetapi banyak orang tidak melihatnya. Terkadang itu sesuatu yang penting yang orang mungkin perlu bereaksi terhadapnya, seperti "Kami akan punya bayi!" atau "Band ini sedang melakukan konser kejutan di bar Drunkin 'Clam!". Dalam kasus terakhir, maka teman-teman yang lain kemungkinan akan perlu bereaksi, terutama jika mereka tertarik pada band itu.

Jika teman Anda ingin menjaga rahasia antara Anda dan mereka, mereka mungkin tidak akan mempostingnya ke dinding Facebook mereka, mereka akan menghubungi Anda secara langsung dan memberi tahu Anda. Bayangkan sebuah skenario di mana Anda memberi tahu seorang gadis bahwa Anda ingin bertemu dengannya di sebuah restoran untuk kencan. Alih-alih memanggilnya langsung dan memintanya, Anda mempostingnya di dinding Facebook agar semua teman Anda dapat melihatnya. Ini bekerja, tetapi jika Anda memiliki mantan cemburu, maka dia bisa melihat itu dan muncul di restoran untuk merusak hari Anda.

Ketika memutuskan apakah akan membangun pendengar acara untuk mengimplementasikan sesuatu, pikirkan analogi ini. Apakah komponen ini perlu menempatkan bisnis mereka di luar sana agar dilihat oleh siapa pun? Atau apakah mereka perlu memanggil seseorang secara langsung? Hal-hal dapat menjadi sangat mudah berantakan jadi berhati-hatilah.

arjabbar
sumber
0

Analogi berikut ini dapat membantu Anda untuk memahami pemrograman I / O yang didorong oleh peristiwa dengan menggambar garis sejajar dengan garis tunggu di meja resepsionis Dokter.

Memblokir I / O seperti, jika Anda berdiri di antrian, resepsionis meminta seorang pria di depan Anda untuk mengisi formulir dan dia menunggu sampai selesai. Anda harus menunggu giliran Anda sampai orang itu menyelesaikan formulirnya, ini menghalangi.

Jika pria lajang membutuhkan waktu 3 menit untuk diisi, pria ke-10 harus menunggu hingga 30 menit. Sekarang untuk mengurangi 10 orang ini menunggu waktu, solusinya, meningkatkan jumlah resepsionis, yang mahal. Inilah yang terjadi di server web tradisional. Jika Anda meminta info pengguna, permintaan selanjutnya oleh pengguna lain harus menunggu sampai operasi saat ini, mengambil dari Database, selesai. Ini meningkatkan "waktu untuk menanggapi" dari permintaan ke-10 dan itu meningkat secara eksponensial untuk pengguna ke-n. Untuk menghindari hal ini, server web tradisional membuat utas (setara dengan peningkatan jumlah resepsionis) untuk setiap permintaan tunggal, mis., Pada dasarnya ia membuat salinan server untuk setiap permintaan yang merupakan interms mahal dari konsumsi CPU karena setiap permintaan akan membutuhkan sistem Operasi benang. Untuk meningkatkan aplikasi,

Didorong oleh Peristiwa : Pendekatan lain untuk meningkatkan "waktu respons" antrian adalah menggunakan pendekatan berdasarkan peristiwa, di mana orang yang ada dalam antrean akan menyerahkan formulir, diminta mengisi dan kembali setelah selesai. Karena itu resepsionis selalu dapat menerima permintaan. Inilah yang telah dilakukan javascript sejak awal. Di browser, javascript akan merespons acara klik pengguna, gulir, geser, atau ambil basis data, dan sebagainya. Ini dimungkinkan dalam javascript secara inheren, karena javascript memperlakukan fungsi sebagai objek kelas satu dan mereka dapat diteruskan sebagai parameter ke fungsi lain (disebut panggilan balik), dan dapat dipanggil saat menyelesaikan tugas tertentu. Inilah yang tepatnya dilakukan node.js di server. Anda dapat menemukan lebih banyak info tentang pemrograman yang digerakkan oleh acara dan memblokir i / o, dalam konteks simpul di sini

vijay kumar
sumber