HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📝
프론트엔드 스쿨 교안(1기)
/
📝
Javascript
/
📝
14. promise, async, await
📝

14. promise, async, await

1. callback 지옥을 벗어나자!2. Promise3. 실전예제4. async, await(에이씽크, 어웨잇)5. 호출스택

1. callback 지옥을 벗어나자!

  • 콜백 함수는 아래처럼 나중에 실행할 함수!
const 버튼 = document.querySelector('.button'); 버튼.addEventListener('click', function(){}); // 버튼.addEventListener('click', '다른 곳에서 짠 함수이름'); // ex('click', helloworld100) // function helloworld100() { // console.log('hello world'); // console.log('hello world'); // } // 버튼.addEventListener('click', ()=>{});
function 함수하나(출력){ console.log('hello'); 출력('world'); } 함수하나(console.log);
 
  • 위에 코드가 작성이 되는 이유는 함수나 메서드는 결국 어떤 기능을 가리키고 있는 식별자이기 때문
let hojun = console.log; hojun('hello world');
 
  • 함수 하나가 로그인 기능이었고, 이 로그인 기능 이후에 계좌 연동, 이미지 로드 등의 기능이 실행되어야 한다면 아래와 같이 여러 함수들의 중첩이 일어남
function 로그인(){ if (로그인성공) { 이미지로드(); 계좌연동(...계좌연동 이후 일어나는 코드...); ... } }
 
  • 이렇게 연결된 것을 아래처럼 풀어낼 수 있음
user.login( id, pw, 로그인성공, 로그인실패, 이미지로드, 계좌연동...)
 
  • 여기서는 콜백지옥(callback hell)이 잘 감이 안오지만 아래처럼 실제 코드로 짜보면 감이옴.
userData.login( id, pw, (user) => { userData.getData( user, (userData) => { ..콜백에 콜백.. }, (fail) => { ..콜백에 콜백.. } ); }, (fail) => { ..콜백에 콜백.. }, (user) => { //이미지 로드 ..콜백에 콜백.. }, (user) => { // 계좌 연동 ..콜백에 콜백.. }, );
 
  • 콜백 지옥 코드 체험(모던자바스크립트 예제)
콜백
자바스크립트 호스트 환경이 제공하는 여러 함수를 사용하면 비동기(asynchronous) 동작을 스케줄링 할 수 있습니다. 원하는 때에 동작이 시작하도록 할 수 있죠. setTimeout 은 스케줄링에 사용되는 가장 대표적인 함수입니다. 실무에서 맞닥뜨리는 비동기 동작은 아주 다양합니다. 스크립트나 모듈을 로딩하는 것 또한 비동기 동작입니다(이 예시는 뒤에서 구체적으로 다룰 예정입니다).
콜백
https://ko.javascript.info/callbacks
콜백
 
 

2. Promise

  • 이러한 콜백 지옥을 탈출할 수 있게 만들어주는 것이 promise!
  • promise는 언제 내가 널(콜백함수) 다시 불러줄지 모르겠지만, 언젠가 널 다시 불러주겠다 약속하겠다는 뜻
  • 노드를 하실 것이라면 반드시 알아야 함!
  • (2022년에는 대부분) (promise를 여러개 실행할 수 있는) Promise.all보다는 allSettled(실패한 것만 추려내는 기능이 있음)를사용할 것으로 보임
let p = new Promise(function(resolve, reject) { // 실행코드 }); // resolve(value) — 작업이 성공적으로 마무리되면 호출, 결과는 value에 담김 // reject(error) — 작업이 실패시 호출, error는 error에 담김
 
// 쉬운 예제 let p = new Promise(function(resolve, reject) { resolve('hello world'); }).then(메시지 => { alert(메시지); return 메시지.split(' ')[0] }).then(메시지 => { alert(메시지); return 메시지[0] }).then(메시지 => { alert(메시지); }); let p = new Promise(function(resolve, reject) { // resolve('hello world'); reject('hello world'); }).then(메시지 => { alert(메시지); return 메시지.split(' ')[0] }).then(메시지 => { alert(메시지); return 메시지[0] }).then(메시지 => { alert(메시지); }).catch(메시지 => { alert('catch 실행!! :' + 메시지); }); let p = new Promise(function(resolve, reject) { // resolve('hello world'); reject('hello world'); }).then(메시지 => { alert(메시지); return 메시지.split(' ')[0] }).then(메시지 => { alert(메시지); return 메시지[0] }).then(메시지 => { alert(메시지); }).catch(메시지 => { alert('catch 실행!! :' + 메시지); }); let p = new Promise(function(resolve, reject) { // resolve('hello world'); reject('hello world'); }).then(메시지 => { alert(메시지); throw Error("에러 발생!") return 메시지.split(' ')[0] }).then(메시지 => { alert(메시지); return 메시지[0] }).then(메시지 => { alert(메시지); }).catch(메시지 => { alert('catch 실행!! :' + 메시지); }); let p = new Promise(function(resolve, reject) { // resolve('hello world'); // reject('hello world'); resolve('hello world'); }).then(메시지 => { alert(메시지); throw Error("에러 발생!") return 메시지.split(' ')[0] }).then(메시지 => { alert(메시지); return 메시지[0] }).then(메시지 => { alert(메시지); }).catch(메시지 => { alert('catch 실행!! :' + 메시지); });
  • console.log로 promise를 찍어보세요.
  • 왜 하냐고요? 비동기가 핵심입니다.
  • 성공과 실패만 합니다. 중립은 없습니다. 대기(pending)는 있습니다.
// 모던자바스크립트 예제 let promise = new Promise(function(resolve, reject) { // 프라미스가 만들어지면 executor 함수는 자동으로 실행됩니다. // 1초 뒤에 일이 성공적으로 끝났다는 신호가 전달되면서 result는 'done'이 됩니다. setTimeout(() => resolve("끝남!"), 1000); }); console.log('hello world'); console.log(promise);
// 모던자바스크립트 예제 (살짝 수정) let promise = new Promise(function(resolve, reject) { // 프라미스가 만들어지면 executor 함수는 자동으로 실행됩니다. // 1초 뒤에 일이 성공적으로 끝났다는 신호가 전달되면서 result는 'done'이 됩니다. setTimeout(() => resolve("이제야 끝남!"), 10000); }); console.log('hello world'); console.log(promise);
let promise = new Promise(function(resolve, reject) { // 프라미스가 만들어지면 executor 함수는 자동으로 실행됩니다. // 1초 뒤에 일이 성공적으로 끝났다는 신호가 전달되면서 result는 'done'이 됩니다. setTimeout(() => resolve(console.log('데이터를 성공적으로 받아옴')), 1000); }); console.log('hello world');
  • 일부러 에러를 던져줄 수도 있습니다.
// 모던자바스크립트 예제 (살짝 수정) let promise = new Promise(function(resolve, reject) { // 1초 뒤에 에러와 함께 실행이 종료되었다는 신호를 보냅니다. setTimeout(() => reject("에러에러!!"), 3000); });
let promise = new Promise(function(resolve, reject) { // 1초 뒤에 에러와 함께 실행이 종료되었다는 신호를 보냅니다. setTimeout(() => reject(new Error("에러 발생!")), 3000); });
// 실행하지 마세요. pending에 빠집니다. let promise = new Promise(function(resolve, reject) { console.log('hello world') });
 
  • 전체적인 모습은 아래와 같습니다. 실행이 되는 코드는 Node에서 살펴보도록 하겠습니다.
new Promise((resolve, reject) => {...code...}) .then(...code...) .then(...code...) .finally(...code...) .catch(...code...); // <-- .catch에서 에러 객체를 다룰 수 있음
 
  • 아래 코드를 콘솔에서 실행해보세요.
// 모던자바스크립트 예제 new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 1000); // (*) }).then(function(result) { // (**) alert(result); // 1 return result * 2; }).then(function(result) { // (***) alert(result); // 2 return result * 2; }).then(function(result) { alert(result); // 4 return result * 2; });
 
// 모던자바스크립트 예제 (살짝 수정) new Promise(function(resolve, reject) { setTimeout(() => reject('error'), 1000); }).then(function(result) { alert(result + ' : 잘 수행!'); return result + 'one'; }).catch(function(result) { alert(result + ' : 애러 발생!'); // 1 return result + 'two'; }).then(function(result) { alert(result + ' : 잘 수행!'); // 2 return result + 'three'; });
 
// 모던자바스크립트 예제 let p = new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 10000); // (*) }); console.log('hello world'); let p2 = p.then(function(result) { // (**) console.log(result); // 1 return result * 2; }); console.log('hello world2'); let p3 = p2.then(function(result) { // (***) console.log(result); // 2 return result * 2; }); console.log('hello world3'); let p4 = p3.then(function(result) { console.log(result); // 4 return result * 2; });
  • 다음 예제는 프라미스 체이닝이 아님!
// 모던자바스크립트 예제 let promise = new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 1000); }); promise.then(function(result) { alert(result); // 1 return result * 2; }); promise.then(function(result) { alert(result); // 1 return result * 2; }); promise.then(function(result) { alert(result); // 1 return result * 2; });
 
  • 모던 자바스크립트의 콜백함수 애러처리
// 모던자바스크립트 // 정리 전 loadScript('1.js', function(error, script) { if (error) { handleError(error); } else { // ... loadScript('2.js', function(error, script) { if (error) { handleError(error); } else { // ... loadScript('3.js', function(error, script) { if (error) { handleError(error); } else { // 모든 스크립트가 로딩된 후, 실행 흐름이 이어집니다. (*) } }); } }) } }); // 정리 후 loadScript("/article/promise-chaining/one.js") .then(script => loadScript("/article/promise-chaining/two.js")) .then(script => loadScript("/article/promise-chaining/three.js")) .then(script => { // 스크립트를 정상적으로 불러왔기 때문에 스크립트 내의 함수를 호출할 수 있습니다. one(); two(); three(); });

3. 실전예제

  • 아래 예제를 확인해보면 1과 2가 출력되고 나중에 console.log가 출력이 되기 때문에 비동기라는 것을 알 수가 있습니다.
fetch('https://raw.githubusercontent.com/paullabkorea/coronaVaccinationStatus/main/data/data.json') .then(function(response) { return response.json(); }) .then(function(json) { console.log(json); return json }) console.log(1); console.log(2);
  • 실전예제
Response.json() - Web APIs | MDN
The method of the interface takes a stream and reads it to completion. It returns a promise which resolves with the result of parsing the body text as . Note that despite the method being named json(), the result is not JSON but is instead the result of taking JSON as input and parsing it to produce a JavaScript object.
Response.json() - Web APIs | MDN
https://developer.mozilla.org/en-US/docs/Web/API/Response/json
Response.json() - Web APIs | MDN
fetch('https://raw.githubusercontent.com/paullabkorea/coronaVaccinationStatus/main/data/data.json') .then(function(response) { console.log(1); return response.json(); }) .then(function(json) { console.log(2); console.log(json); return json }) .then(function(json) { console.log(3); console.log(json.filter(s => s['시·도별(1)'] === '전국')); return })
// 1차 접종 퍼센트를 구해주세요! fetch('https://raw.githubusercontent.com/paullabkorea/coronaVaccinationStatus/main/data/data.json') .then(function(response) { console.log(1); return response.json(); }) .then(function(json) { console.log(2); console.log(json); return json }) .then(function(json) { console.log(3); console.log(json.filter(s => s['시·도별(1)'] === '전국').map(obj => obj['1차 접종 퍼센트'])); return })
fetch('https://raw.githubusercontent.com/paullabkorea/coronaVaccinationStatus/main/data/data.json') .then(function(response) { console.log(1); throw Error('애러났어유!') return response.json(); }) .then(function(json) { console.log(2); console.log(json); return json }) .then(function(json) { console.log(3); console.log(json.filter(s => s['시·도별(1)'] === '전국')); return }) .catch(err => alert(err))
 

4. async, await(에이씽크, 어웨잇)

  • Ajax도 에이작스죠? 이거 어싱크라고 하시는 분이 많습니다.
  • 일부 런타임에서는 async 없이도 await을 사용할 수 있습니다. 앞으로는 다른 런타임도 그렇게 될 것이고요. (top level await)
// 모던 자바스크립트 예제 async function f() { return 100; } f().then(alert); // 100
 
// 모던 자바스크립트 예제 (살짝 수정) async function f() { return 100; } f().then(function(result) { // (**) alert(result); // 1 return result * 2; }).then(function(result) { // (***) alert(result); // 2 return result * 2; }).then(function(result) { alert(result); // 4 return result * 2; });
 
  • await은 (크롬을 제외한 브라우저의 런타임) 일반 함수에서는 사용이 불가합니다.
// 모던 자바스크립트 예제 async function f() { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("완료!"), 1000) }); let result = await promise; // 프라미스가 이행될 때까지 기다림 (*) alert(result); // "완료!" } f();
 
  • 시간을 3초로 하여 어떤 결과가 나오는지 봅시다.
// 모던 자바스크립트 예제 (살짝 수정) async function f() { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("완료!"), 3000) }); let result = await promise; // 프라미스가 이행될 때까지 기다림 (*) alert(result); // "완료!" return 100 } f().then(function(result) { // (**) alert(result); // 1 return result * 2; }).then(function(result) { // (***) alert(result); // 2 return result * 2; }).then(function(result) { alert(result); // 4 return result * 2; });
 
// 모던 자바스크립트의 잘못된 예제 (https://ko.javascript.info/async-await) // 보라님에게 제보해주세요.ㅎㅎ 시간이 지나면서 보완이 되어벼러서 잘못된 내용이 된 것입니다. let response = await fetch('https://raw.githubusercontent.com/paullabkorea/coronaVaccinationStatus/main/data/data.json'); let data = await response.json();
 
  • 추가된 문법
    • top-level-await
    • for await (변수 of 프로미스배열) 문법
    •  

 

5. 호출스택

  • js 코드
function one(){ two(); } function two(){ three(); } function three(){ console.log('end'); }
  • (호출 스택) 쌓이면서 하나씩 빠짐
three() two() one() anonymous // 가상 전역 컨텍스트, 이것도 마지막에 빠짐
  • 그러면 아래 코드는?
console.log(1); setTimeout(function(){ console.log(2); }, 1000) // setTimeout(()=> console.log(2), 1000) console.log(3);
 

 
이벤트루프 연습장.pptx
35.7KB
  • 호출스택이 모두 끝나야 백그라운드 실행합니다. 중간에 실행되는 경우 없어요.
  • 이벤트 루프를 설명하는 영상은 매우 많고, 설명이 조금씩 다릅니다. 이유는 대부분이 복잡한 개념을 단순화 해서 설명하고 있기 때문이에요.
  • 저는 'Node.js 교과서' 기준으로 설명으로 설명해드리도록 하겠습니다.
notion image
 
console.log(1); setTimeout(실행, 1000) console.log(3); function 실행(){ console.log(2); }
  1. 메모리에 실행함수 적재
  1. 호출스택에 anonymous 들어감
  1. console.log(1)이 호출 스택에 쌓임
  1. console.log(1)이 실행되어 console에 1을 찍고 스택에서 사라짐
  1. 백그라운드에 timer(실행, 1) (계속 시간을 카운팅하는 중)
  1. console.log(3)이 스택에 쌓임
  1. console.log(3)이 실행되어 console에 3를 찍고 스택에서 사라짐
  1. anonymous 사라짐
  1. 1초가 지나가면 백그라운드에서 태스크 큐로 '실행' 함수를 가져옴(백그라운드에서 없어짐)
  1. 태스크 큐에서 실행함수를 호출 스택으로 가져옴
  1. '실행'함수 위에 console.log(2)가 쌓임
  1. console.log(2)이 실행되어 console에 2를 찍고 스택에서 사라짐
  1. '실행' 함수가 호출 스택에서 사라짐
 
참고영상
[10분 테코톡] 🍗 피터의 이벤트루프
🙋‍♀️ 우아한테크코스의 크루들이 진행하는 10분 테크토크입니다. 🙋‍♂️'10분 테코톡'이란 우아한테크코스 과정을 진행하며 크루(수강생)들이 동료들과 학습한 내용을 공유하고 이야기하는 시간입니다. 서로가 성장하기 위해 지식을 나누고 대화하며 생각해보는 시간으로 자기 주도적인...
[10분 테코톡] 🍗 피터의 이벤트루프
https://youtu.be/wcxWlyps4Vg
[10분 테코톡] 🍗 피터의 이벤트루프
Jake Archibald: In The Loop - JSConf.Asia
Have you ever had a bug where things were happening in the wrong order, or particular style changes were being ignored? Ever fixed that bug by wrapping a sec...
Jake Archibald: In The Loop - JSConf.Asia
https://youtu.be/cCOL7MC4Pl0
Jake Archibald: In The Loop - JSConf.Asia
What the heck is the event loop anyway? | Philip Roberts | JSConf EU
JavaScript programmers like to use words like, "event-loop", "non-blocking", "callback", "asynchronous", "single-threaded" and "concurrency".We say things li...
What the heck is the event loop anyway? | Philip Roberts | JSConf EU
https://youtu.be/8aGhZQkoFbQ
What the heck is the event loop anyway? | Philip Roberts | JSConf EU
자바스크립트와 이벤트 루프 : NHN Cloud Meetup
기술을 공유하고 함께 성장해가는 개발 문화, NHN이 추구하는 가치입니다.
자바스크립트와 이벤트 루프 : NHN Cloud Meetup
https://meetup.toast.com/posts/89
자바스크립트와 이벤트 루프 : NHN Cloud Meetup
latentflip.com
http://latentflip.com/loupe/
 

 
(실습) 실전 로그인 페이지 만들기!
JSON Generator - Tool for generating random data
Specifies number of repeats of array item. Repeatable array must contains only two items: first is repeat tag, second is item that must be repeated. If no arguments is specified item will be repeated from 0 to 10 times. If min argument is specified, item will be repeated that many times.
JSON Generator - Tool for generating random data
https://json-generator.com/
[ '{{repeat(10, 7)}}', { _id: '{{objectId()}}', id: '{{firstName()}}', pw: '{{guid()}}', index: '{{index()}}', picture: 'http://placehold.it/32x32', age: '{{integer(20, 40)}}', eyeColor: '{{random("blue", "brown", "green")}}', name: '{{firstName()}} {{surname()}}', gender: '{{gender()}}', company: '{{company().toUpperCase()}}', email: '{{email()}}', phone: '+1 {{phone()}}', address: '{{integer(100, 999)}} {{street()}}, {{city()}}, {{state()}}, {{integer(100, 10000)}}', grade: '{{random("새싹", "일반", "실버", "골드", "다이아몬드", "관리자")}}' } ]