MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

현재 번역은 완벽하지 않습니다. 한국어로 문서 번역에 동참해주세요.

 이 글은 이벤트 및 이벤트 핸들링(event handling)에 대한 개요로서, 웹 페이지가 열려있는 동안 일어나는 사건(incident)에 대해 반응할 수 있도록 하는 코드 설계 패턴에 대해 설명하고, 현 세대의 웹 브라우저에서 핸들링할 수 있는 사건의 종류에 대해 요약한다.

 이벤트와 이벤트 핸들링은 웹 페이지가 사용자에 의해 열린 상태를 유지하는 동안 일어나는 사건에 대한 반응을 구현하기 위한 자바스크립트의 핵심적인 기술이다. 이러한 사건에는 페이지가 전시(display)되기 위한 준비과정 중 일어나는 사건, 웹 페이지상의 컨텐츠와 사용자의 상호작용에 의한 사건, 브라우저가 실행되는 기반 장치와 관련된 사건, 매체 스트림(media stream) 재생이나 애니메이션 시간 간격 등 기타 요인에 의한 사건 등이 있다.

 이벤트와 이벤트 핸들링은 자바스크립트가 처음 도입된 시점부터 중심적인 역할을 했으며, 이와 함께 브라우저의 렌더링 아키텍처 역시 단일 처리경로(single pass) 페이지 렌더링으로부터 리플로우(reflow) 기반, 이벤트 구동식(driven) 페이지 렌더링 개념으로 바뀌었다.

 최초에는 브라우저는 페이지의 모든 부분에 대한 문법분석(parse), 처리(process), 그리기(draw) 및 사용자에게 표현(present)까지의 모든 과정이 끝날 때까지 대기하고, 페이지 작업이 끝나면 그 상태로 바뀌지 않고 새 페이지 요청이 있어서 가져오기(fetch)작업이 일어나기 전까지는 그대로의 모습을 유지했다. 

 리플로우 기반 이벤트 구동식 페이지 렌더링 개념으로 바뀐 뒤에는 브라우저는 처리, 그리기, 컨텐츠 표현(present), 반복순환작업을 다시 개시하도록 하는 이벤트 트리거에 대한 대기 등의 작업을 반복순환(loop)하여 수행한다. 이 이벤트 트리거라는 것은 이벤트를 발생하게 하는 사건을 이르는 것으로서, 네트워크상의 자원 로드 완료( 예 : 이미지가 다운로드되어 화면상에 그릴 수 있게 됨), 브라우저에 의한 자원의 문법분석 완료( 예 : HTML페이지 처리가 끝남) 페이지의 컨텐츠와 사용자와의 상호작용(예 : 버튼을 클릭한다) 등이 이러한 사건이 될 수 있다.

 더글라스 크록포드는 An inconvenient API : The theory of the DOM(불편한 API : DOM의 이론)이라는 제목의 강연에서 이러한 변화를 여러 단원에 걸쳐 설명하였는데, 본래의 작업 흐름에서 이벤트 구동식 브라우저의 작업 흐름으로 바뀌는 것을 다음과 같이 보여주었다.

A comparison of the sequential and event-driven browser load sequences.

 두 번째 그림에 보이는 처리방식은 마지막 단계의 작업흐름을 변화시킴으로써 첫 번째 그림의 단일 경로 처리흐름에서 반복순환 흐름으로 바뀐 것을 보여준다. 두 번째 그림은 Paint작업이 끝나면 새로운 이벤트 발생에 대한 처리(이벤트 핸들링)를 하기 위해 이벤트를 기다리게 된다. 이 혁신적인 개념을 이용하면 자원을 다 획득하지 않았더라도 페이지를 부분적으로 렌더링하는 것이 가능하며, 최초에는 자바스크립트에 의해 발전된 이벤트 구동에 의한 동작 효과적으로 구현할 수 있다. (이 강의는 여기를 포함한 다양한 경로로 볼 수 있다) 현재 모든 자바스크립트 코드 실행 환경에서는 이벤트와 이벤트 핸들링을 사용한다.

이벤트 설계 패턴

이벤트 시스템은 근본적으로는 단순한 프로그래밍 설계 패턴이다. 이 패턴는 기본적으로 이벤트의 종류와 다음 사항에 대해 합의된 약속을 기반으로 한다.

  • 각 이벤트를 가리키는 이벤트명 문자열
  • 각 이벤트의 핵심 프로퍼티를 나타내기 위한 자료구조의 형식
  • 각 이벤트를 발동할 자바스크립트 객체

패턴을 구현하기 위해서는 다음이 필요하다.

  • 위에서 약속된 자료구조를 인수로 받는 자바스크립트 함수를 정의한다.
  • 이벤트를 발동할 객체에 약속된 해당 이벤트의 이벤트명을 사용하여 위의 함수를 등록한다.

이 함수는 리스너(listener) 또는 핸들러(handler)라는 혼용된 명칭으로 불린다. 이 패턴은 커스텀 이벤트에 관한 글에서 설명한 대로의 완전한 커스텀 이벤트를 사용하여 쉽게 구현할 수 있다. 이 패턴은 사용자 입력, 브라우저 활동 등에 의해 발동되는 다양한 이벤트를 정의하는 최신 웹 브라우저에서도 많이 사용한다.

 최신 웹 브라우저는 이 이벤트 패턴을 표준화된 방식으로 구현한다. 브라우저는 어떤 이벤트의 프로퍼티를 나타내는 자료 구조로서  EventPrototype 객체를 원천으로 하는 어떤 객체를 사용한다. 또한 이러한 자료구조를 핸들링할 함수에 대한 등록 메소드로서 addEventListener 메소드를 사용하는데 이것은 인수로서 이벤트명과 핸들러 함수를 받는다. 마지막으로 브라우저는 이벤트 발동자(emitter)로 수많은 객체를 정의하며 또한 이 객체들에 의해 생성되는 여러 이벤트형(event type)을 정의한다.

버튼 이벤트 핸들러 데모

하나의 예시로서 브라우저 button 요소(element)는 'click'이라는 이름의 이벤트를 마우스 클릭 또는 터치스크린의 경우 손가락 터치에 반응하여 발동시킨다. 버튼은 HTML 페이지에서 다음과 같이 정의할 수 있다.

<button id="buttonOne">Click here to emit a 'click' event</button>

그리고 자바스크립트 코드에서 'click' 이벤트에 대한 리스너로서의 함수, 즉 핸들러로 사용할 함수를 정의한다.

var example_click_handler = function (ev){
    var objKind = (ev instanceof Event) ? "EventPrototype" : "ObjectPrototype";
    alert("We got a click event at " + ev.timeStamp + " with an argument object derived from: " + objKind );
};

그 다음 해당 Button 객체와 함께 위의 함수를 등록하는데, 첫 번째 방법은 HTML 페이지의 DOM(문서 객체 모델) 표현법을 이용하여 다음과 같이 스크립트상에서 나타내는 방법이다. 

var buttonDOMElement = document.querySelector('#buttonOne');
buttonDOMElement.addEventListener('click', example_click_handler);

또 다른 방법은 HTML 페이지 상에서 'onclick' 애트리뷰트의 값으로 핸들러로 쓸 함수를 대입시키는 것인데, 보통 이 방식은 매우 단순한 웹 페이지에서나 쓰인다.

This code relies on the agreement that there is a kind of event called 'click' which will call any listener (or 'handler') function with an Event object argument (actually, in this case a derivative MouseEvent object) and which will be fired by HTML button elements after user interaction. The code has no visible effect until a user interacts with the button either by placing the mouse pointer over the HTML button and clicking on the left mouse button or by placing a finger or stylus of some kind on the screen above the HTML button; when that happens, the buttonDOMElement Javascript object would call the example_click_handler function with an Event object as an argument. The function, in turn, would perform whatever action was chosen by the programmer, in this case to open an HTML alert dialog. Note that the handler has access to the ev object since it is passed as an argument; the object has information about the event, notably the time at which the event occurred.

As a second example, much modern Javascript integrated into web pages is wrapped into an event function call to ensure that the code is only executed when the HTML has been processed and is available for alteration or decoration. For example, code might be attached as:

var funcInit = function(){
    // user code goes here and can safetly address all the HTML elements from the page
    // since the document has successfully been 'loaded'
}
document.addEventListener('DOMContentLoaded', funcInit);

so that this code will only be executed after the document object emits the 'DOMContentLoaded' event because the HTML has been parsed and Javasript objects created representing each of the nodes of the HTML document. Note that in this example, the code does not even name the event argument to the function because the code never needs to use the data structure describing the event; rather, the code merely needs to wait to run until after then event has happened.

The pattern is therefore easy to learn and implement. The difficulty with events comes from learning the wide variety of events which are generated in modern web browsers. There is also some subtlety in learning how to write the handler functions since such code works asynchronously and potentially will run repeatedly but in slightly different situations.

Notable events

Web browsers define a large number of events so it is not practical to list them all. The Event Reference attempts to maintain a list of the standard Events used in modern web browsers.

In general, we can distinguish events of different kinds based on the object emitting the event including:

  • the window object, such as due to resizing the browser,
  • the window.screen object, such as due to changes in device orientation,
  • the document object, including the loading, modification, user interaction, and unloading of the page,
  • the objects in the DOM (document object model) tree including user interactions or modifications,
  • the XMLHttpRequest objects used for network requests, and
  • the media objects such as audio and video, when the media stream players change state.

although this list is currently incomplete.

Some notable events are:

Note: This list of will need work to make relevant; that work is awaiting some global reorganization work on the documents. This will also need finding a good explanation of the events involved during page loading, such as discussed partially in this web page or in this Stack Overflow question.

  • the global object window emits an event called 'load' when the page has finished rendering, meaning that all resources have been downloaded and acted upon, so that the scripts have been run and the images displayed,
  • the global object window emits an event called 'resize' when the height or the width of the browser window is changed by a user,
  • the DOM object document representing the HTML document emits an event called 'DOMContentLoaded' when the document has finished loading,
  • the DOM node objects such as div or button emit an event called 'click' when the user presses the mouse button while the mouse pointer is on top of the DOM node in the HTML page.

 

The Event object hierarchy

The web browser defines many events of different kinds. Each definition includes, as the data structure passed to the handler function, an object which inherits from the EventPrototype object.

A partial diagram of the class hierarchy of event objects is:

Note: This diagram is incomplete.

The Web API Documentation contains a page defining the Event object which also includes the known DOM event subclasses of the Event object.

Documents

Three sources on the MDN (Mozilla Developer Network) web site are particularly useful for programmers wanting to work with events:

 

 

 

문서 태그 및 공헌자

 이 페이지의 공헌자: PineMt
 최종 변경: PineMt,