이벤트 기반 프로그래밍은 언제 사용해야합니까?


65

작업이 완료되면 콜백을 전달하거나 프로그램의 다른 기능에서 함수를 트리거하여 작업을 수행했습니다. 무언가가 끝나면 함수를 직접 트리거합니다.

var ground = 'clean';

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

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

그러나 나는 프로그래밍에서 여러 가지 다른 전략에 대해 읽었으며, 강력하지만 이해하지는 못했지만 이벤트 기반입니다 (내가 읽은 방법은 "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);

이벤트 기반 프로그래밍의 객관적인 강점과 약점을 이해하고 싶습니다. 다른 함수 내에서 모든 함수를 호출하는 것입니다. 어떤 프로그래밍 상황에서 이벤트 기반 프로그래밍이 적합합니까?


2
옆으로을 사용할 수 있습니다 $(document).bind('snow', shovelShow). 익명 함수로 감싸지 않아도됩니다.
Karl Bielefeldt

4
이벤트 중심 프로그래밍과 많은 공통적 인 "반응 형 프로그래밍"에 대해 배우고 싶을 수도 있습니다.
Eric Lippert

답변:


75

이벤트는 최근 과거의 발생을 설명하는 통지입니다.

이벤트 중심 시스템의 일반적인 구현은 이벤트 디스패처핸들러 기능 (또는 가입자 )을 사용합니다. 디스패처는 핸들러를 이벤트 (jQuery 's bind) 까지 연결하는 API 와 구독자 ( triggerjQuery)에 이벤트를 공개하는 메소드를 제공 합니다. IO 또는 UI 이벤트에 대해 이야기 할 때 일반적 으로 마우스 클릭과 같은 새로운 이벤트를 감지하여 디스패처에 전달 하는 이벤트 루프 도 있습니다 . JS-land에서는 디스패처 및 이벤트 루프가 브라우저에서 제공됩니다.

키 누르기 및 클릭에 응답하여 사용자와 직접 상호 작용하는 코드의 경우 이벤트 중심 프로그래밍 (또는 기능적 반응성 프로그래밍 과 같은 변형 )은 거의 피할 수 없습니다. 프로그래머는 사용자가 언제 어디에서 클릭을할지 알지 못하므로 GUI 프레임 워크 또는 브라우저를 사용하여 이벤트 루프에서 사용자의 조치를 감지하고 코드에 알립니다. 이 유형의 인프라는 네트워킹 응용 프로그램 (cf NodeJS)에도 사용됩니다.

함수를 직접 호출하는 대신 코드에서 이벤트 를 발생 시키는 예제 에는 더 흥미로운 트레이드 오프가 있습니다. 이는 아래에서 설명합니다. 주요 차이점은 이벤트 게시자 ( makeItSnow)가 통화 수신자를 지정하지 않는다는 것입니다. 그것은 다른 곳에서 연결되어 있습니다 ( bind예제 호출 ). 이것을 불을 잊어 버리는 것입니다 . makeItSnow눈이 내리고 있다는 사실을 세상에 알리지 만, 누가 듣고 있는지, 다음에 어떻게되는지, 언제 일어날지를 신경 쓰지 않습니다. 단순히 메시지를 방송하고 손에서 먼지를 털어냅니다.


따라서 이벤트 중심 접근 방식은 메시지 발신자를 수신자와 분리합니다. 이것이 제공하는 한 가지 장점은 주어진 이벤트에 여러 핸들러가있을 수 있다는 것입니다. gritRoads기존 shovelSnow핸들러에 영향을주지 않고 스노우 이벤트에 함수를 바인딩 할 수 있습니다. 응용 프로그램을 연결하는 방식에 유연성이 있습니다. 비헤이비어를 끄 bind려면 코드를 탐색하지 않고 호출 을 제거 하면 동작의 모든 인스턴스를 찾을 수 있습니다.

이벤트 중심 프로그래밍의 또 다른 장점은 크로스 커팅 문제를 해결할 수 있다는 것입니다. 이벤트 디스패처는 Mediator 의 역할을 하며 Brighter 와 같은 일부 라이브러리 는 파이프 라인을 사용하므로 로깅 또는 서비스 품질과 같은 일반 요구 사항을 쉽게 플러그인 할 수 있습니다.

전체 공개 : 더 밝게 Huddle에서 개발되었습니다.

수신자와 이벤트 송신자를 분리하는 세 번째 장점은 이벤트 를 처리 할 때 유연성을 제공한다는 것 입니다. 각 유형의 이벤트를 자체 스레드에서 처리하거나 (이벤트 디스패처가 지원하는 경우) RabbitMQ 와 같은 메시지 브로커에 발생한 이벤트를 배치 하고 비동기 프로세스로 처리하거나 밤새 대량으로 처리 할 수 ​​있습니다. 이벤트 수신자는 별도의 프로세스 또는 별도의 시스템에있을 수 있습니다. 이를 위해 이벤트를 발생시키는 코드를 변경할 필요가 없습니다! 이것은 "마이크로 서비스"아키텍처의 기본 아이디어입니다. 자율 서비스는 메시징 미들웨어를 애플리케이션의 중추로하여 이벤트를 사용하여 통신합니다.

이벤트 중심 스타일의 다소 다른 예를 보려면 도메인 기반 디자인 을 사용하여 도메인 이벤트 를 사용하여 집계를 개별적으로 유지하십시오. 예를 들어 구매 내역에 따라 제품을 추천하는 온라인 상점을 생각해보십시오. 에 대한 비용을 지불 Customer하면 구매 내역을 업데이트 ShoppingCart해야합니다. ShoppingCart집계는 통지 할 수 Customer일으키기에 의해 CheckoutCompleted이벤트를; 는 Customer이벤트에 대한 응답으로 별도의 트랜잭션으로 업데이트받을 것입니다.


이 이벤트 중심 모델의 주요 단점은 간접적 인 것입니다. IDE를 사용하여 이벤트를 탐색 할 수 없기 때문에 이벤트를 처리하는 코드를 찾기가 더 어려워졌습니다. 구성에서 이벤트가 바운드되는 위치를 파악하고 모든 핸들러를 찾았 으면합니다. 한 번에 더 많은 것들을 머릿속에 보관해야합니다. 코드 스타일 규칙이 여기에 도움이 될 수 있습니다 (예 : 모든 호출을 bind하나의 파일에 저장). 정신 건강을 위해 하나의 이벤트 디스패처 만 사용하고 일관되게 사용해야합니다.

또 다른 단점은 이벤트를 리팩토링하기 어렵다는 것입니다. 이벤트 형식을 변경해야하는 경우 모든 수신자를 변경해야합니다. 이제 소프트웨어 릴리스를 동기화해야하므로 이벤트 구독자가 다른 시스템에있을 때 더욱 악화됩니다.

특정 상황에서는 성능이 문제가 될 수 있습니다. 메시지를 처리 ​​할 때 디스패처는 다음을 수행해야합니다.

  1. 일부 데이터 구조에서 올바른 핸들러를 찾으십시오.
  2. 각 핸들러에 대한 메시지 처리 파이프 라인을 빌드하십시오. 이것은 많은 메모리 할당을 포함 할 수 있습니다.
  3. 핸들러를 동적으로 호출하십시오 (언어가 요구하는 경우 리플렉션 사용).

이것은 스택에서 새 프레임을 푸시하는 것과 관련된 일반 함수 호출보다 확실히 느립니다. 그러나 이벤트 중심 아키텍처가 제공하는 유연성 덕분에 느린 코드를보다 쉽게 ​​분리하고 최적화 할 수 있습니다. 백그라운드에서 어려운 작업을 처리하는 동안 즉시 요청을 처리 할 수 ​​있기 때문에 비동기 프로세서에 작업을 제출할 수있는 기능이 큰 도움이됩니다. 어쨌든 DB와 상호 작용하거나 화면에 물건을 그리는 경우 IO 비용은 메시지 처리 비용을 완전히 깎아냅니다. 조기 최적화를 피하는 경우입니다.


요약하면, 이벤트는 느슨하게 결합 된 소프트웨어를 빌드하는 좋은 방법이지만 비용이없는 것은 아닙니다. 예를 들어 응용 프로그램의 모든 함수 호출을 이벤트 로 바꾸는 것은 실수 입니다. 의미있는 건축 부문을 만들기 위해 이벤트를 사용하십시오.


2
이 답변은 내가 선택한 올바른 5377의 답변과 동일합니다. 선택이 더 정교 해지기 때문에 선택하도록 변경하고 있습니다.
Viziionary

1
이벤트 중심 코드의 속도가 중요한 단점입니까? 가능할 것 같지만 잘 모르겠습니다.
raptortech97

1
@ raptortech97 확실히 그럴 수 있습니다. 특히 빠를 필요가있는 코드의 경우 내부 루프에서 이벤트를 보내지 않을 수 있습니다. 다행스럽게도 이러한 상황에서는 일반적으로 수행해야 할 작업이 잘 정의되어 있으므로 이벤트를 유연하게 추가 할 필요가 없습니다.
Jules

1
또한 모든 것이 메시지 (이벤트) 인 액터 모델 주위에 구축 된 일부 언어 (예 : Erlang)가 있습니다. 이 경우 컴파일러는 메시지 / 이벤트를 직접 함수 호출 또는 통신으로 구현할지 여부를 결정할 수 있습니다.
Brendan

1
"성능"을 위해서는 단일 스레드 성능과 확장 성을 구분해야한다고 생각합니다. 단일 스레드 성능의 경우 메시지 / 이벤트가 더 나빠질 수 있지만 (추가 비용없이 0으로 함수 호출로 변환 될 수 있으며, 더 나쁘지 않을 수 있음) 확장 성은 거의 모든면에서 우수합니다 (예 : 최신 멀티에서 성능이 크게 향상 될 수 있음) -CPU 및 향후 "많은 CPU"시스템).
Brendan

25

이벤트 기반 프로그래밍은 프로그램이 수행하는 이벤트 순서를 제어하지 않을 때 사용됩니다. 대신 프로그램 흐름은 사용자 (예 : GUI), 다른 시스템 (예 : 클라이언트 / 서버) 또는 다른 프로세스 (예 : RPC)와 같은 외부 프로세스에 의해 지시됩니다.

예를 들어, 일괄 처리 스크립트는 수행해야 할 작업을 알고 있습니다. 이벤트 기반 이 아닙니다 .

워드 프로세서가 거기에 앉아 사용자가 입력을 시작할 때까지 기다립니다. 키 누르기는 내부 문서 버퍼를 업데이트하는 기능을 트리거하는 이벤트입니다. 프로그램은 입력하려는 내용을 알 수 없으므로 이벤트 중심이어야합니다.

대부분의 GUI 프로그램은 사용자 상호 작용을 중심으로 구축되므로 이벤트 중심입니다. 그러나 이벤트 기반 프로그램은 GUI로 제한되지 않으며 이는 대부분의 사람들에게 가장 친숙한 예입니다. 웹 서버는 클라이언트가 유사한 관용구를 연결하고 따를 때까지 기다립니다. 컴퓨터의 백그라운드 프로세스도 이벤트에 응답 할 수 있습니다. 예를 들어 주문형 바이러스 검색 프로그램은 OS에서 새로 생성되거나 업데이트 된 파일과 관련된 이벤트를 수신 한 다음 해당 파일에서 바이러스를 검색 할 수 있습니다.


18

이벤트 기반 애플리케이션에서 이벤트 리스너 개념은 더 많은 느슨하게 결합 된 애플리케이션 을 작성할 수있는 기능을 제공합니다 .

예를 들어, 타사 모듈 또는 플러그인은 데이터베이스에서 레코드를 삭제 한 다음 receordDeleted이벤트 를 트리거 하고 나머지는 이벤트 리스너에게 맡겨서 작업을 수행 할 수 있습니다. 트리거링 모듈이 누가이 특정 이벤트를 듣고 있는지 또는 다음에 어떻게해야하는지 알지 못하더라도 모든 것이 잘 작동합니다.


6

내가 추가하려는 간단한 비유가 나를 도왔습니다.

응용 프로그램의 구성 요소 (또는 객체)를 대규모 Facebook 친구 그룹으로 생각하십시오.

친구 중 한 사람이 당신에게 무언가를 말하고 싶을 때, 그들은 당신에게 직접 전화하거나 Facebook 벽에 게시 할 수 있습니다. 그들은 자신의 페이스 북에 게시 할 때, 사람 를보고 그것에 반응하지만, 많은 사람들이하지 않습니다. 때때로 "우리는 아기를 낳고 있습니다"와 같이 사람들이 그것에 반응해야 할 중요한 일이 있습니다. 또는 "So-and-so 밴드가 Drunkin 'Clam 바에서 깜짝 콘서트를하고 있습니다!" 마지막 경우, 특히 친구가 해당 밴드에 관심이있는 경우 나머지 친구가 이에 반응해야 할 것입니다.

친구가 당신과 그들 사이에 비밀을 유지하기를 원한다면, 아마도 그것을 Facebook 벽에 게시하지 않았을 것입니다. 그들은 당신에게 직접 전화를 걸고 말할 것입니다. 당신이 데이트를 위해 식당에서 그녀를 만나고 싶다고 말하는 소녀를 시나리오로 묘사하십시오. 그녀에게 직접 전화를 걸고 묻지 않고 모든 친구들이 볼 수 있도록 Facebook 벽에 게시합니다. 이것은 효과가 있지만, 질투하는 전남이 있다면, 그녀는 그것을보고 식당에 나타나 하루를 망치게 할 수 있습니다.

무언가를 구현하기 위해 이벤트 리스너에 빌드할지 여부를 결정할 때이 비유에 대해 생각하십시오. 이 구성 요소를 다른 사람이 볼 수 있도록 비즈니스를 운영해야합니까? 아니면 누군가에게 직접 전화해야합니까? 일이 너무 쉽게 지저분해질 수 있으므로 조심하십시오.


0

다음 비유는 Doctor 's Reception 데스크에서 대기 라인과 평행을 이루어 이벤트 중심 I / O 프로그래밍을 이해하는 데 도움이 될 수 있습니다.

I / O 차단은 마치 대기열에 서있는 경우 접수자가 앞에있는 사람에게 양식을 작성하도록 요청하고 완료 될 때까지 기다립니다. 녀석이 자신의 형태를 마칠 때까지 차례를 기다려야합니다.

독신자가 3 분을 채우면 10 번째 사람은 30 분까지 기다려야합니다. 이제이 10 번째 직원 대기 시간을 줄이려면 해결책이 될 것입니다. 이것이 전통적인 웹 서버에서 일어나는 일입니다. 사용자 정보를 요청하는 경우 다른 사용자의 후속 요청은 데이터베이스에서 가져 오기와 같은 현재 작업이 완료 될 때까지 기다려야합니다. 이것은 10 번째 요청의 "응답 시간"을 증가시키고 n 번째 사용자에 대해 기하 급수적으로 증가합니다. 이러한 전통적인 웹 서버를 피하기 위해 모든 단일 요청에 대해 스레드 (접수 수신인 수 증가)를 작성합니다. 즉 기본적으로 각 요청마다 운영 체제가 필요하므로 CPU 소비 측면에서 비용이 많이 드는 각 요청에 대한 서버 사본을 작성합니다. 실. 앱을 확장하려면

Event Driven : 대기열의 "응답 시간"을 확장하는 또 다른 방법은 대기열에있는 사람이 양식을 넘기고 작성하여 다시 완료하도록 요청하는 이벤트 기반 접근 방식입니다. 따라서 접수는 항상 요청할 수 있습니다. 이것은 처음부터 자바 스크립트가 수행 한 것입니다. 브라우저에서 자바 스크립트는 사용자 클릭 이벤트, 스크롤, 스 와이프 또는 데이터베이스 가져 오기 등에 응답합니다. 이것은 자바 스크립트에서 본질적으로 가능합니다. 자바 스크립트는 함수를 일급 객체로 취급하고 다른 함수 (콜백이라고 함)에 매개 변수로 전달할 수 있으며 특정 작업이 완료되면 호출 될 수 있기 때문입니다. 이것이 바로 서버에서 node.js가하는 일입니다. 당신은 노드의 맥락에서, 이벤트 기반 프로그래밍 및 I / O를 차단에 대한 자세한 정보를 찾을 수 있습니다 여기에

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.