비동기적 코드
setTimeout()
특정 시간이 경과 한 뒤 특정 코드를 한번 실행합니다.
- 실행할 함수 또는 다른곳에 정의 된 함수 참조.
- mlisecond 단위로 측정.
- 취소시 clearTimeout('매개변수 명')
setInterval()
각각의 호출 간에 일정한 시간 간격으로 특정 코드를 반복적으로 실행합니다.
function displayTime(){
let date = new Date();
let time = date.toLocaleTimeString();
document.getElementById('demo').textContent = time;
}
const createClock = setInterval(displayTime, 1000); // 등록시
clearInterval(createClock); //취소시
- 순환 Timeouts. setTimeout()을 사용하는 또 다른 방법입니다.
- setInterval을 사용하는 대신 setTimeout()을 이용해서 같은 코드를 반복적으로 실행합니다
let i =0; setTimeout(function run() { consol.log(i); i++; setTimeout(run, 100); }, 100);
- 순환 setTimeout과 setInterval의 차이는? 순환 timeout은 실행과 실행 사이에 지연을 보장 합니다. 100ms이면, 간격은 코드 실행과 상관 없이 동일 합니다. setInterval은 코드를 실행하는데 40ms 가 걸리면 간격이 60ms에 불과 합니다. 설정된 간격에 코드 실행 간격도 같이 포함이 됩니다.
- setTimeout()을 재귀적으로 사용할 떄 각 반복은 다음 반복을 실행하기 전에 또 하나의 대기시간을 설정 합니다.
- requestAnimationFrame() 브라우저에서 애니메이션을 효율적으로 실행하기 위해 만들어진 특수한 반복 함수. 일반적인 화면 재생률 60Hz, 브라우저 초당 60FPS 입니다. 이 속도보다 빠르게 설정하면, 과도한 연산이 실행되어, 프레임 손실이 일어나게 됩니다. 취소도 가능 하나 "clear"가 아닌 "cancle"로 cancleAnimationFrame(rAF); 같은 형식으로 실행합니다.
Promise
Promise에 대해서
어떤 작업의 중간 상태를 나타내는 오브젝트 - 미래에 어떤 종류의 결과가 반환됨을 표현해줍니다. 일반적으로 비동기 작업 결과를 반환하는데 얼마의 시간이 걸리는지 보다는 그 결과를 사용할 수 있는지 여부에 더 관심을 가집니다. Promise로 가장 많이 하는 작업은 Promise를 반환하는 웹 API를 사용하는 것입니다.
function handleCallButton(evt){
setStatusMessage("calling...");
navigator.mediaDevices.getUserMedia({video: true, audio: true})
.then(chatStream => {
selfViewElem.srcObject = chatStream;
chatStream.getTracks().forEach(track => mypeerconnection.addTrack(track, chatStream));
setStatusMessage('connected');
}).catch(error => {
console.log(error);
setStatusMessage("Failed")
});
}
- Promise는 한번에 성공/실패 중 하나의 결과값을 가집니다. 하나의 요청에 두번 성공하거나 실패 할 수 없습니다. 또한 이미 성공한 작업이 다시 실패로 돌아 갈수 없고, 실패한 작업이 성공으로 돌아갈수없습니다.
- Promise가 생성되면 그 상태는 성공도 실패도 아닌 peddding 상태라고 부릅니다.
- Promise 결과가 반환되면 결과에 상관 없이 resolved 상태라고 부릅니다.
- 성공적으로 처리된 Promise는 fullfilled 상태이면 promise의 다음 .then() 블럭 내부의 excutor()함수에 Promise에서 반환된 값이 파라미터로 전달 됩니다.
- 실패한 Promise는 rejected 상태이며, promise가 rejeect 됐는지를 나타내는 에러 메시지를 포함한 결과가 반환 됩니다.
Runnning code in response to multiple promise fullfilling
example:
let a = fetch(url);
let b = fetch(url);
let c = fetch(url);
Promise.all([a,b,c]).then(values=>{
...
});
배열의 모든 Promise가 fulfill이면,. then() 블록의 excutor 함수로의 매개변수로 Promise 결과의 배열을 전달합니다. 배열 하나라도 reject 되면, 전체 결과가 reject 됩니다
response에 대한 응답 값을 원하면, 단순한 결과만 넘겨주는 것이 아닙니다. 결과에 대해 처리해주는 것을 목적으로 Promise를 사용합니다. 예를 들어 a 반환 값 text이고, b의 반환 값은 blob 객체일 때, promise.all()을 사용하고 싶은 상황을 말합니다.
function fetchAndDecode(url, type){
return fetch(url).then(response =>{
if( type === 'blob'){
return response.blob();
} else if (){
return response.text();
}
})
}
Runnning some final code after a promise fullfilling / reject
promise가 fullfilled 인지, rejected 인지, 관계없이 Promise가 완료된 후 최종 코드 블록을 실행하는 경우도 있습니다. 최근. finally() method를 사용하여, promise 체이닝 끝에 배치하여, 코드 반복을 줄일 수 있습니다.
mypromise
.then( response => {
doSomething(response);
}).catch(e => {
returnError(e);
}).finally(()=>{
funFinallyCode();
});
Building your own custom promise
Using the Promise() constructor
promise() constructor를 사용하여, 사용자 정의 promise를 만들 수 있습니다.
let timeoutPromise = new Promise((resolve, reject) = {
setTimeout(()=> {
resolve();
}, 2000);
})
resolve()와 reject()는 Promise의 fulfill/reject 일 때의 수행하기 위해 호출하는 함수입니다.
reject() 메서드를 사용하여, Promise가 reject상태 일 때, 전달할 값을 지정할 수 있습니다. resolve()도 동일합니다. promise가 reject 되면 에러는. catch() 블록으로 전달됩니다. 이전 예시를 좀 더 확장하면 reject()을 추가하고, promise 가 fulfill 일 때 다른 메시지도 전달할 수 있습니다. 출력할 메시지와 메시지를 출력할 때까지 기다릴 시간입니다.
function timeoutPromise(message, interval) {
return new Promise((resolve, reject) => {
if (message === '' || typeof message !== 'string') {
reject('Message is empty or not a string');
} else if (interval < 0 || typeof interval !== 'number') {
reject('Interval is negative or not a number');
} else {
setTimeout(function(){
resolve(message);
}, interval);
}
});
};
- 첫째, 메시지 유효성 검사. 메시지 비어있거나, 에러메시지 함께 Promise를 reject 합니다
- interval 유효성,숫자 아니거나 음수 에러메시지로 rejcet 합니다.
- 마지막 함수 setTimeout()함수에 지정된 interval에 맞춰 Promise를 resolve 합니다.
function promisifyRequest(request) {
return new Promise(function(resolve, reject) {
request.onsuccess = function() {
resolve(request.result);
};
request.onerror = function() {
reject(request.error);
};
});
}
jake archibald's ldb libray. 이 라이브러리는 Promise constructor()의 비동기 작업 응용을 보여주는 유용한 라이브러리입니다. 클라이언트 측에서 데이터를 저장하고 검색하기 위한 구식 Callback 기반 API로 Promise와 함께 사용하는 IndexedDB API입니다.
- request의 sucess event가 실행 될 때, onSuccess 핸들러에 의해 fullfill된 Promise의 request result를 반환 합니다
- request의 error event가 실행 되면, onError 핸들러에 의해 reject된 Promise의 request error 반환 합니다.
async와 await
ECMAS2017에 추가된 내용입니다. Promise 기반 코드르 좀 더 쓰기 쉽고 읽기 쉽게 만들어 줍니다.
The basics of async/await
function hello(){ return "hello"};
hello();
// expression async
async function hello() { return "hello"};
hello();
// expresion arrow function
let hello = async() => {
return 'hello';
}
//기본적으로 위에 2가지로 표현이 됩니다. 호출은 아래와 같습니다
hello().then( (vlaue) => console.log(value));
hello().then(consol.log(value));
async를 함수와 같이 사용하면, 결과를 직접 반환하는 게 아니라 Promise를 반환하게 됩니다. 동기식 함수 await 사용을 위한 지원과 함께 실행되는 잠재적인 overhaed를 피할 수 있습니다. 함수가 async로 선언이 되면, 핸들링만 추가하면 javascript 엔진이 최적화를 알아서 해줍니다.
Rewriting promise cod with async/await
fecth('url').then({
response => response.blob()
}).then({
mblob => {
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
}
}).catch(e=>{
consol.log('error :' +e.message);
})
async function myFetch(){
let response = await fetch();
let myBolob = await response.blob();
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
}
myFetch.catch(e => {
// async 함수
})
await는 async function 안에서만 쓸 수 있습니다. 비동기 코드를 실행할 블록을 정의하려면 비동기 함수를 생성해야 합니다. 단순 promise() 함수와의 차이점은. then() 블록을 사용하여 작업을 이거나는 대신 메서드 호출 전에 await 키워드를 사용하여, 반환된 결과를 변수에 할당합니다. await 키워드는 javascript 런타임이 이 라인에서 비동기 코드를 일시 중지하여 비동기 함수 호출이 결과를 반환될 때까지 기다리게 합니다. 외부의 다른 동기 코드를 실행은 될 수 있습니다.
Adding error handling
try/catch구문을 사용하여 async/await 구조에서 사용할 수 있습니다.
// 방안 1
async function myFetch(){
try{
let response = await fetch();
let myBolob = await response.blob();
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
} catch (e) {
console.log(e);
}
}
myFetch();
//방안 2
async function myFetch(){
let response = await fetch();
return response.blob();
}
myFetch().then({
...생략
}).catch( (e) =>{
})
async/await는 promise의 상위에 만들어져서 promsie의 모든 기능을 사용할 수 있습니다. promise.all() 함수를 포함합니다.
async function fetchAndDecode(url, type){
let response = await fetch('url');
let content ;
switch (type){
case 'text':
content = await response.blob();
break;
case 'blob':
content = await response.text();
break;
}
return console;
}
async function displayContent(){
let data1 = fetchAndDecode('url', 'blob');
let data2 = fetchAndDecode('url', 'text');
let values = await Promise.all([data1, data2]);
let objectURL = URL.createObjectURL(values[0]);
let sampleText = values[1];
}
displayContent().catch((e) => {
console.log(e);
})
async/await는 마치 동기식 코드처럼 보이게 됩니다. 함수 블록에 여러 개의 await키워드를 사용하면, Promise가 fullfilled가 되기 전까지 다음 await를 기다리게 됩니다, promise에 의해 오히려 느려지는 것을 의미합니다. 각 await는 이전의 작업이 끝날 때까지 기다립니다.
function timeoutPromise(interval){
return new Promise((reslove, reject) => {
setTimeout(()=>{
reslove();
}, interval);
});
};
async function timeTest(){
//...구성 차이는 여기서 납니다.
// 수행시간 6초
await timeoutPromise(3000);
await timeoutPromise(3000);
// 변수에 넣고, await를 합니다.
// 먼저 실행하고, 나온 결과물을 변수에 저장해놨다가, 수행 시킵니다.
// 수행 시간 3초
const time1 = timeoutPromise(3000)
const time2 = timeoutPromise(3000)
await time1;
await time2;
};
let startTime = Date.now();
timeTest().then(()=>{
let finishTime = Date.now();
let timeToken = finishTime - startTime;
alert(timeToken);
})
변수에 await을 사용하여 결과를 호출하면, -작업이 거의 동시에 시작됐기 때문에, promise도 거의 동시에 fullfiled 됩니다. 성능이 떨어지기 시작하면, 위의 상황을 의심해봐야 합니다. 사소한 단점은 비동기로 실해될 Promise가 있다면 async 함수 안에 항상 await를 써야 한다는 것입니다. async 키워드를 class/object의 메서드에 사용하여 Promise를 반환하게 만들 수 있다는 것입니다.
class Person {
//...
constructor(name){
this.name= name;
// ... 생략
}
async greeting(){
return await Promise.resolve(`${this.name}`);
}
farewell(){
console.log(`${this.name}`);
}
};
let han = new Person('min');
han.greeting().then(console.log);