1. 비동기적 프로그래밍
사용자(User)가 언제 클릭할지, 터치할지, 또는 타이핑할지 당신은 전혀 알 수 없다.
비동기적 실행이 사용자 입력 하나 때문에 필요한 건 아니다.
자바스크립트 애플리케이션은 단일 스레드에서 동작 - 한 번에 한 가지 일만 할 수 있음.
일반적으로 동기적 실행을 하는 언어를 사용했었다면 더 어렵게 느껴질 수 있음
- 자바스크립트의 비동기적 프로그래밍 구분되는 3가지 패러다임
1) 콜백: 제너레이터나 프라미스 외에도 이벤트 처리 등에 유용하게 쓸 수 있음.
2) 프라미스
3) 제너레이터 (비동기적 프로그래밍을 전혀 지원하지 않음) : 비동기적으로 사용하려면 프라미스나 특수한 콜백과 함께 사용.
- 사용자 입력 외에, 비동기적 테크닉을 사용해야 하는 경우
1) Ajax 호출을 비롯한 네트워크 요청
2) 파일을 읽고 쓰는 등의 파일 시스템 작업
3) 의도적으로 시간 지연을 사용하는 기능 (알람 기능)
* 비유 *
콜백과 프라미스
예약하지 않고 분주한 음식점에 방문한 경우.
콜백: 줄을 서서 기다리지 않고 전화번호를 받아서 자리가 나면 전화를 줌. - 각자 다른 일을 하다가 자리가 나서 호출(전화)함.
프라미스: 자리가 났을 때 진동하는 호출기를 당신에게 넘겨줌. - 음식점 안에서 호출을 함.
2. 콜백
자바스크립트의 오래된 비동기적 메커니즘
사용자 입력과 타임아웃을 처리하면서 이미 콜백을 사용함.
console.log('Before timeout: ' + new Date()); // Before timeout: Fri May 01 2020 13:44:49 GMT+0900 (대한민국 표준시)
function f() {
console.log('after timeout: ' + new Date());
}
setTimeout(f, 60* 1000); // 1
console.log('I happen after setTimeout'); // I happen after setTimeout
console.log('Me too'); // Me too
// 1분 후, f() 콜백함수 출력 됨.
// after timeout: Fri May 01 2020 13:46:33 GMT+0900 (대한민국 표준시)
1) setInterval과 clearInterval
const start = new Date();
let i = 0;
const intervalId = setInterval(function() {
let now = new Date();
if(now.getMinutes() !== start.getMinutes() || ++i > 10)
return clearInterval(intervalId);
console.log(`${i}: ${now}`);
}, 5 * 1000)
2) 스코프와 비동기적 실행
비동기적 실행에서 혼란스럽고 에러도 자주 일어나는 부분은 스코프와 클로저가 비동기적 실행에 영향을 미침.
함수를 호출하면 항상 클로저가 만들어짐.
function countDown() {
let i;
console.log('countDown');
for(i = 5; i >= 0; i--) {
setTimeout(function() {
console.log(i === 0 ? 'go': i);
}, (5 - i) * 1000);
}
}
countDown();
function countDown() {
console.log('countDown');
for(let i = 5; i >= 0; i--) {
setTimeout(function() {
console.log(i === 0 ? 'go': i);
}, (5 - i) * 1000);
}
}
countDown();
콜백이 어느 스코프에서 선언했느냐에 따라 실행이 달라짐. (let i)
3) 오류 우선 콜백
노드가 점점 인기를 얻어가던 시기에 오류 우선 콜백이라는 패턴이 생김.
const fs = require('fs');
const fname = 'may_or_may_not'
fs.readFile(fname, function(err, data) {
if(err) return console.error(`error reading file ${fname}: ${err.message}`);
console.log(`${fname} contents: ${data}`);
});
4) 콜백 헬
콜백을 사용해 비동기적으로 실행할 수 있긴 하지만, 현실적인 단점.
한 번에 여러가지를 기다려야 한다면 콜백을 관리하기가 상당히 어려워짐.
3. 프라미스
콜백의 단점을 해결하려는 시도 속에서 만들어짐.
일반적으로 안전하고 관리하기 쉬운 코드를 만들 수 있게 됨.
프라미스 기반 비동기적 함수를 호출하면 그 함수는 promise인스턴스를 반환함.
프라미스는 성공하거나 실패하거나 두 가지뿐 프라미스를 결정됐다
프라미스는 객체이므로 어디든 전달할 수 있다는 점. 콜백에 비해 간편한 장점.
비동기적 처리를 여기서 하지 않고 다른 함수에서 처리하게 하고 싶다면 프라미스를 넘기기만 하면 됨.
(마치 음식점에서 받은 예약 호출기를 친구에게 맡기는 것과 비슷)
function countDown(seconds) {
return new Promise(function(resolve, reject) {
for(let i = seconds; i >= 0; i--) {
setTimeout(function() {
if(i > 0) console.log(i + '...');
else resolve(console.log('GO'));
}, (seconds - i) * 1000);
}
});
}
1) 이벤트
이벤트가 일어나면 이벤트 발생을 담당하는 개체에서 이벤트가 일어남.
노드에는 이미 이벤트를 지원하는 모듈 EventEmitter가 내장돼 있습니다.
const EventEmitter = require('events').EventEmitter;
class Countdown extends EventEmitter {
constructor(seconds, superstitious) {
super();
this.seconds = seconds;
this.supperstitious = !!superstitious;
}
go() {
const countdown = this;
return new Promise(function(resolve, reject) {
for(let i = countdown.seconds; i >= 0; i--) {
setTimeout(function() {
if(countdown.supperstitious && i === 13)
return reject(new Error('oh my god'));
countdown.emit('tick', i);
if(i === 0) resolve();
}, (countdown.seconds - i) * 1000);
}
});
}
}
const c = new Countdown(5);
c.on('tick', function(i) {
if(i > 0) console.log(i + '...');
});
c.go()
.then(function() {
console.log('go');
})
.catch(function(err) {
console.log.error(err.message);
})
'Front-End' 카테고리의 다른 글
[JS] Mouseover Event (0) | 2020.05.07 |
---|---|
[ React ] React 셋팅 (0) | 2020.05.06 |
[JS] 맵과 셋 (ES6) (0) | 2020.04.30 |
[JS] 객체와 객체지향 프로그래밍 (0) | 2020.04.30 |
[JS] 배열 (0) | 2020.04.30 |