Callback Event Queue에서 하나씩 꺼내서 동작시키는 루프를 말한다.
자바스크립트는 싱글 스레드 기반 언어이기 때문에, 한번에 하나씩 작업을 진행한다.
자바스크립트는 이벤트 루프를 이용해서 비동기 방식으로 동시성을 지원한다.
동시성에 대한 처리는 자바스크립트 엔진을 구동하는 환경, 즉 브라우저나 Node.js가 담당한다.
비동기 호출을 위해 사용하는 함수들은 Web API영역에 따로 정의되어있고,
이벤트 루프와 테스크 큐 같은 장치도 자바스크립트 엔진 외부에 구현되어 있다.
자바스크립트가 '단일 스레드' 기반 언어라는 말은 '자바스크립트 엔진이 단일 호출 스택을 사용한다' 라는 관점에서만 사실이다.
자바스크립트가 구동되는 환경에서는 주로 여러 개의 스레드가 사용되며, 이런 구동 환경이 단일 호출 스택을 사용하는 자바 스크립트 엔진과 상호 연동하기 위해 사용하는 장치가 '이벤트 루프'인 것이다.
Run to Completion
: 자바스크립트의 함수가 실행되는 방식으로, 하나의 함수가 실행되면 이 함수의 실행이 끝날 때까지는 다른 어떤 작업도 중간에 끼어들지 못한다는 의미이다.
태스크 큐는 콜백 함수들이 대기하는 Queue 형태의 배열이라 할 수 있고,
이벤트 루프는 호출 스택이 비워질 때 마다 큐에서 콜백 함수를 꺼내와서 실행하는 역할을 해준다.
* 모든 비동기 API들은 작업이 완료되면 콜백함수를 태스크 큐에 추가한다.
* 이벤트 루프는 호출 스택이 비워졌을 때 태스크 큐의 첫 번째 태스크를 꺼내와 실행한다.
콜백 지옥이란 콜백 함수를 익명 함수로 전달하는 과정에서 또 다시 콜백 안에 함수 호출이 반복되어 코드의 가독성이 떨어지는 현상을 말합니다.
해결법 1 : Promise
자바스크립트 비동기 처리에 사용되는 객체로 ES6에서 추가되었다.
프로미스의 구조
new Promise(function(resolve, reject) {
// ...
});
프로미스는 3가지 상태가 있다.
resolve
를 실행하면 Fullfilled 상태가 된다. 이후 then
을 이요하여 처리 결과 값을 받을 수 있다.reject
를 실행하면 rejected 상태가 된다. 이후 실패한 이유를 Catch
로 받을 수 있다.에러를 잡는방식으로 reject를 사용하는 방식, catch를 사용하는 방식 2가지가 있는데, 보통 catch를 사용한다. reject를 사용하면 then에서 발생하는 에러를 잡지 못하기 때문이다.
Promise는 Promise를 반환하기 때문에 다음 작업을 체이닝 하여 작성할 수 있다.
그렇기 때문에 콜백지옥을 해결 할 수 있다.
해결법 2 : async await
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("완료!"), 1000)
});
let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)
alert(result); // "완료!"
}
f();
async는 function 앞에 붙여서 활용한다.
function 앞에 async를 붙이면 해당 함수는 항상 Promise를 반환한다. Promise가 아닌 값을 반환하더라도 resolved Promise로 값을 감싸 반환한다.
await은 Promise가 처리될 때까지 기다린다.
Promise가 처리되면 그 결과와 함께 실행이 재개된다.
Promise 보다 가독성이 좋기 때문에 자주 사용된다.
<body>
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
</body>
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent);
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
이벤트 버블링
특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성을 의미한다.
위의 코드에서 <div class="three"></div>
를 클릭하게 된다면
three
two
one
순서로 찍히게 된다.
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent, {
capture: true // default 값은 false입니다.
});
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
이벤트 캡쳐
위위 코드와 위 코드의 차이점은 {capture: true}
가 있다는 점이다. 해당 옵션으로 인해 이벤트 버블링과는 반대로 최상위 요소인 body 태그부터 해당 태그까지 찾아 내려간다.
그렇기 때문에 <div class="three"></div>
를 클릭하게 된다면
one
two
three
순서로 찍히게 된다.
이벤트 버블링 혹은 캡쳐를 막고 싶다면 콜백함수안에서 event.stopPropagation()
라는 웹 API를 사용하면 된다. 만약 예제에 있는 logEvent에서 사용했다면
버블링에서는 three, 캡쳐링에서는 one만 출력된다.
이벤트 위임
<ul class="itemList">
<li>
<input type="checkbox" id="item1">
<label for="item1">이벤트 버블링 학습</label>
</li>
<li>
<input type="checkbox" id="item2">
<label for="item2">이벤트 캡쳐 학습</label>
</li>
</ul>
var inputs = document.querySelectorAll('input');
inputs.forEach(function(input) {
input.addEventListener('click', function(event) {
alert('clicked');
});
});
만약 다음과 같이 input태그에 이벤트 리스너를 추가한다면 위 2개의 input 태그에서는 정상적으로 작동할 것이다.
하지만 이벤트 리스너가 추가된 이후 동적으로 새로운 리스트 아이템이 추가된다면 새로 추가된 input 태그에는 이벤트 리스너가 등록되어 있지 않다.
이를 해결하기 위해
var itemList = document.querySelector('.itemList');
itemList.addEventListener('click', function(event) {
alert('clicked');
});
다음과 같이 리스트 아이템의 상위 태그인 ul 태그에 이벤트 리스너를 추가하게 된다면, 이벤트 버블링에 의해서 동적으로 추가된 리스트 아이템들도 이벤트를 감지할 수 있게 된다.
출처 : 이벤트 버블링, 이벤트 캡처 그리고 이벤트 위임까지
프로토타입 != 클래스의 상속 -> js에서는 클래스가 없기 때문.
js에서는 복사를 통한 상속 또한 존재하지 않는다. -> JS는 객체자체를 복사하거나 코드 내용을 복사하는 등의 깊은복사를 수행할 수 없기 때문이다. JS에서는 원시값,객체의 참조값 만이 복사할 수 있다.
prototype은 클래스, 객체의 내용 복사 없이도 상속을 구현할 수 있게 해주는 방법이다.
prototype은 연결이다.
new 연산자와 함수를 사용하면 새로운 빈 객체를 메모리 상에 생성함.
생성된 빈 객체가 this에 바인딩 된다.
함수안에 return이 없다면 이 this가 리턴된다.
.__proto__
: 객체와 객체를 연결하는 링크객체는 자신의 원형이라고 할 수 있는 객체가 있다면 그 객체를 가리키는 __proto__
링크를 자동으로 가짐.
함수의 경우, 함수가 만들어 질때 함수의 프로토타입 객체도 같이 만들어진다. 이후 그림처럼 순환참조 관계를 가진다.
new + 함수로 만들어진 객체라면 만들어진 새로운 객체의 __proto__
링크가 Person 객체의 프로토타입 객체를 가리키게 된다.
만약 진짜 존재하지 않는 경우, Object의 프로토타입 객체까지 찾아가는데 Object의 프로토타입 은 null이기 때문에 탐색을 종료하고, undefined를 리턴한다.
이 상황에서 chiris객체에 sayHello가 추가될까?
Person.prototype.sayHello 가 덮어씌워질까?
(읽기전용은 Object.defineProperty 로 설정할 수 있다.)
-> sayHello가 읽기전용 메소드인 경우, JS가 엄격모드라면 에러가 발생하고, 비 엄격 모드라면 아무일도 일어나지 않는다
-> 읽기 전용이 아니라면 chris.sayHello 가 추가된다. 하지만 이렇게 된다면 정상적인 접근으로는 기존의 sayHello에 접근할 수 없다. 이 현상을 오바라이딩이 아닌 가려짐
이라고 표현한다.
타입스크립트는 자바스크립트로 컴파일 된 후 실행된다. 그렇기 때문에 자바스크립트에 의존적이고, 컴파일 언어이다.
장점 :
단점 :
Content Delivery Network 은 지리적 제약 없이 전 세계 사용자에게 빠르고 안전하게 콘텐츠를 전송할 수 있는 콘텐츠 전송 기술을 말한다.
CDN은 서버와 사용자 사이의 물리적인 거리를 줄여 콘텐츠 로딩에 소요되는 시간을 최소화한다.
각 지역에 캐시 서버(edge)를 분산 배치해, 근접한 사용자의 요청에 원본 서버가 아닌 캐시 서버가 콘텐츠를 전달한다.
보통 이미지, 동영상, 미디어, CSS, JS 같은 정적 파일을 호스팅한다.
장점 :
단점 :
자식 노드의 개수가 2개 이상인 트리를 말한다. 또 노드내의 데이터가 1개 이상일 수 있다.
노드 내 최대 데이터 수가 n개 라면 n차 B-Tree라고 말한다.
노드들이 한쪽으로 치우쳐 연결리스트의 형태가 되는 것을 방지하여 검색 효율을 높인다.
어느 한 데이터의 검색은 효율적이지만, 모든 데이터를 한번 순회하는데에는 트리의 모든 노드를 방문해야 하므로 비효율적이다.
성립조건 :
오직 리프 노드에만 데이터를 저장하고 리프노드가 아닌 노드에서는 자식 포인터만 저장한다.
리프노드끼리는 LinkedList로 연결되어 있다.
중간 노드에서 키가 중복될 수 있다.
장점
리프 노드를 제외하고 데이터를 저장하기 않기 때문에 메모리를 더 확보할 수 있다.
Full Scan을 하는 경우 B+Tree는 리프노드에만 데이터가 저장되어 있고, 리프 노드끼리 연결되어 있기 때문에 선형 시간이 소모된다. 반면 B-Tree는 모든 노드를 확인해야 한다.
인덱스 컬럼은 부등호를 이요한 순차 검색 연산이 자주 발생하는데, B-Tree나 Hash Table에 비해 훨씬 성능이 좋다.