9.Event(별100개) , 작성중 …ing
1.Event란
- 이벤트란 어떤 사건을 의미한다. 이벤트가 발생하면 그에 맞는 반응을 해줘야한다. 이를위해 이벤트는 일반적으로 함수와 연결되며 그 함수는 이벤트가 발생하기 전에는 실행되지 않다가 이벤트가 발생하면 실행된다. 이 함수를 이벤트 핸드러라 하며 이벤트에 대응하는 처리를 기술한다.
2.이벤트루프(Event Loop)와 동시성 (별 100만개)
-
브라우저는 단일쓰레드에서 이벤트 드리븐 방식으로 동작한다.
-
단일쓰레드라는 말은 곧 하나의 작업(task)만 처리할수 있다는 것을 의미한다. 하지만 실제 웹 애플리케이션에는 많은 task가 동시에 처리되는것처럼 느껴진다. 이처럼 자바스크립트의 동시성을 지원하는 것이 바로 이벤트 루프이다.
-
Call stack(호출 스텍) : 작업이 요청하면(함수가 호출되면) 요청된 작업은 순차적으로 Call Stack에 쌓이게 되고 순차적으로 실행된다. 자바스크립트는 단 하나의 Call Stack을 사용(==단일(싱글)스레드 언어)하기 때문에 task가 종료하기 전까지는 다른 어떤 task도 수행할수 없다.
-
Heap : 동적으로 생성된 객체 인스턴스가 할당되는 영역
이와같이 자바스크립트 엔진은 단순히 작업을 요청하면 Call Stack을 사용하여 요청된 작업을 순차적으로 실행할 뿐이다(=one thread , one call stack, one thing at a time)
하지만 브라우저에서는 이 동시성을 지원하기 위해 필요한 비동기 요청(이벤트를 포함) 처리를 해준다. (여기서 중요한것은 javascript에서 동시성을 지원하는게 아니라 브라우저에서 지원한다는것이다.)
-
Event Queue(Task Queue) : 비동기처리함수의 콜백함수, 비동기식 이벤트 핸들러, Timer함수(setTimeout(),setInterval())의 콜백함수가 보관되는 영역으로 이벤트루프에 의해 특정시점(Call Stack이 비어졌을 때)에 순차적으로 Call Stack으로 이동되어진다.
-
Event Loop(이벤트 루프): Call Stack 내에서 실행중인 Task가 잇는지, Event Queue에 task가 있는지를 반복하여 확인한뒤, Call Stack이 비어있으면 Event Queue내의 task가 Call Stack으로 이동하고 실행한다.
-
동시성이 어떻게 동작하는지 알려주는 예시
function func1() {
console.log("func1");
func2();
}
function func3() {
console.log("func3");
}
function func2() {
setTimeout(function () {
console.log("func2");
}, 0);
func3();
}
func1();
//결과값
// func1
// func3
// func2
-
동작 과정 : func1() 실행 -> func1()이 Call Stack에 올라간다 -> console.log(func1)을 실행한다. -> func2() 실행 ->func2()가 Call Stack에 올라간다 -> setTimeout이 작동한다 -> Web API에 비동기 요청처리를 해준다. -> 이벤트 함수가 Event Queue로 간다 -> func3()가 실행된다. -> func3()이 Call Stack에 올라간다. -> console.log(func3)을 실행한다. -> 이벤트 루프가 Call Stack이 비어있는것을 확인하고 Event Queue에 있는 이벤트함수를 CallStack에 올린다 -> CallStack에 잇는 이벤트함수가 실행된다. -> console.log(“func2”); 실행
-
자세한 영상은 event loop 를 참고하자
3. 이벤트의 종류
- 다 외울순 없으니, 필요할때마다 그때그때 찾아보는걸루~
4. 이벤트 핸드러(이벤트가 발생했을때 실행되는 함수) 등록 (별100만개)
4.1 addEventListner 메소드 방식
- 여러 방법들이 있지만 , addEventListener 메소드 방식 외에는 단점들이 너무 커서 addEventListener을 사용한다
EventTarget.addEventListener(‘eventType’,functionName[, useCapture]);
- useCapture : caputre 사용 여부 , true : capturing false : Bubbling
addEventListener("click", function () {
alert("Clicked!");
});
위와 같은 예제처럼 Dom 요소 즉 EventTarget을 지정하지 않으면 , 전역객체 window가 바인딩된다. 따라서 브라우저 윈도우 어디를 클릭하여도 이벤트 핸들러가 동작한다.
따라서 다음처럼 일반적으로 Dom은 EventTarget을 지정한뒤에 사용한다.
const inputElement = document.querySelector("input");
inputElement.addEventListener("click", function () {
alert("Clicked!");
});
다음과 같은 예시를 주겠다. 이름을 두글자 이상 입력했을때 이벤트를 동작하도록
<input type="text" /> <em></em>
const inputElement = document.querySelector("input");
const emElement = document.querySelector("em");
inputElement.addEventListener("blur", function () {
if (inputElement.value.length < 2) {
emElement.innerHTML = "이름을 2자 이상 입력하세요";
} else {
emElement.innerHTML = "";
}
});
허나 이런코딩은 2자이상이라는 규칙이 바뀌면 이 규칙을 확인하는 모든 코드를 수정해야한다. 따라서 이렇나 방식의 코딩은 바람직하지 않다. 이유는 규모가 큰 프로그램의 경우 수정과 테스트에 소요되는 자원의 낭비도 문제지만 수정에는 거의 대부분 실수가 동반되기 때문이다.
따라서 2자이상이라는 규칙을 상수화하고 함수의 인수로 전달되도록 수정한다. 이렇게 하면 규칙이 변경되어도 함수는 수정하지 않아도 된다.
그런데 addEventListener 메소드의 두번째 매개변수는 이벤트가 발생했을 때 호출될 이벤트 핸들러이다. 이때 두번째 매개변수에는 함수 호출이 아니라 함수 자체를 지정하여야 한다.
function foo() {
console.log("안녕");
}
elem.addEventListener("click", foo()); //이것의 경우 이벤트 이벤트 방법에 어긋난다. 왜냐하면 click이라는 요소가 동작을 해야 이벤트핸들러가 동작하는 것이 이벤트의 실행방법이고 목적인데 , 그에 부합되지 않을 뿐만아니라, 이벤트 발생시까지 대기하지 않고 바로 실행되버리기 때문이다.
elem.addEventListnenr("click", foo); // 이벤트 발생시까지 대기한다.
이처럼 함수 자체를 지정해야하는데, 그렇기에 addEventListener 방식의 경우에는 인수를 전달할수 없는 문제가 발생한다. 왜냐하면 함수에 인수를 전달하기 위해서는 foo(5) 이런식으로 전달해야하는데, 우리는 함수호출이 아닌 함수자체를 지정해서 쓰지 때문이다.
이를 우회하는 방법이 그래서 중요하다.
<input type="text" /> <em></em>
const MIN_USER_NAME_LENGTH = 2; //이름 최소길이
const inputElement = document.querySelector("input");
const emElement = document.querySelector("em");
function checkUserNameLength(n) {
if (inputElement.value.lenth < n) {
emElement.innerHTML = "이름은" + n + "자 이상이어야 합니다";
} else {
elElement.innerHTML = "";
}
}
inputElement.addEventListener('blur' function(){
checkUserNameLength(MIN_USER_NAME_LENGTH);
})
-
결론 : 이 개념을 통해 그동안 궁금했다 addEventListnenr(“click”, foo); 방식과 addEventListener(“click” function(){}) 의 차이점을 명확하게 알게 되었다.
-
addEventListnenr(“click”, foo)의 경우는 이벤트핸드러(이벤트가 발생할시 실행되는 함수)를 인자(아규먼트) 없이 그냥 실행시키고 싶을때 사용하는것이고
-
addEventListener(“click” function(){})의 경우는 인자값이 필요한 경우에 사용하는것이다.
5. 이벤트 핸드러 함수 내부의 this
5.1 addEventListener 메소드 방식
- addEventListener 메소드에서 지정한 이벤트 핸드러는 콜백함수 이지만(콜백함수는 일반적으로 window를 가르킴), 이벤트 핸들러 내부의 this는 이벤트 리스너에 바인딩된 요소(currentTarget)을 가르킨다.
<button>Button</button>
const elem = document.querySelector("button");
elem.addEventListener("click", function (event) {
console.log(this); // <button>Button</button> === elem을 가리킴
console.log(event.currentTarget); //<button>Button</button>
console.log(event.target); //<button>Button</button>
});
- currentTarget : 이벤트 생성 위치
-
target : 이벤트 발생 위치
- currentTarget 과 target의 차이점은 나중에 더 배워보자..
Leave a comment