일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Invalid character found in method name
- jdbc connector
- kafka-connect
- Cannot add or update a child row: a foreign key constraint fails
- 페이지네이션
- 제약 조건
- Path Variable
- kafka connect
- git reflog
- API 설계
- event loop
- 1450
- Query String
- debezium
- 참조무결성
- 23000
- reflog
- code --no-sandbox
- Pagination Optimization
- git rebase -i
- Late row lookup
- 문자열 검증
- Git
- constraint fails
- 페이지네이션 최적화
- kafkaconnect
- foreign key constraint fails
- Cannot delete or update a parent row: a foreign key constraint fails
- programmers
- 1452
- Today
- Total
Kawaii_Jordy
[JS] Event Loop와 비동기(Callback, Promise, Async & Await) 본문
0. Event Loop
- 자바스크립트는 싱글 스레드(single-thread) 프로그래밍 언어다. 즉, 작동시 하나의 콜 스택만을 가지고 있다는 얘기다.
- 브라우저가 제공하는 비동기함수(setTimeout, setInterval, ...)는 Web APIs에 이동하게 되고 작동을 시작한다. 작동이 완료되면, 그 실행 데이터들은 콜백 큐(callback queue)에 등록된다. 콜 스택이 비게되면 콜백 큐의 데이터들이 콜 스택에 들어가 실행되는데, 이를 event loop라고 한다.
function test() { console.log(1); setTimeout(function () { console.log(2); }, 0) console.log(3); } test() // => 1, 3, 2 //setTimeout이 0초에 실행된다 해도, 콜 스택을 다 비우고 실행되기에 제일 나중에 뜬다.
- 만약 모든 함수들이 동기적으로 실행된다면 어떻게 될까? 예를 들어 setTimeout으로 3600초를 걸어버리면, 1시간이 지나 함수가 실행될때 까지 아무런 작업도 진행하지 못하게 될 것이다(blocking).
1. 비동기 다루기
- 비동기 함수들은 Web APIs에서 작업이 마치는 순서에 따라, 콜백 큐에 들어가게 된다. 이 순서 또한 제어하고 싶으면 callback 함수를 이용하면 된다.
1-1. Callback
- 콜백 함수의 뜻은 간단하게 다음과 같다.
- 어떤 함수에 인자로 들어가는 함수.
- 어떤 이벤트에 의해 호출되는 함수(위에 문장과 크게 다르지 않다).
let printString = (somString, callback) => { setTimeout ( () => { console.log(somString) callback() }, Math.floor(Math.random() * 100) + 1 //서버와 통신하는데, 임의의 시간이 걸린다고 가정하자. ) } let printAllString = () => { printString("a", () => { printString("b", () => { printString("c", () => {}) }) }) } printAllString() // a, b, c (각자 실행되는 시간이 다른데도 순서대로 되어있는 것을 볼 수 있다.)
- 즉, 하나의 비동기 함수에 다른 비동기 함수를 인자로 넣어서, 해당 비동기 함수가 끝나면 인자로 넣은 비동기 함수를 실행(callback)시키는 형식이다.
let callback = (err, data) => { if (err) { return throw error('something wrong'); } return data };
- 이런 식으로 콜백함수를 통해 에러를 다룰 수도 있다. (어떤 과정이 잘 끝나면 err에는 null을 넣고 data에는 해당 과정의 data를 넣어 콜백함수를 실행)
- 콜백은 그 과정이 많아지면, 위와 같은 형태로 될 가능성이 높은데, 이를 callback hell이라고 한다. 이를 피하기 위해 나온 것이 Promise다.
1-2. Promise
- 프로미스는 비동기 작업을 수행하는 객체다.
- 프로미스는 생성되고 종료될 때까지 3가지 상태를 갖는다.
- Pending(대기): 아직 비동기 작업이 완료되지 않은 상태.
- Fulfilled(이행): 비동기 작업이 완료되어 결과 값을 반환한 상태.
- Rejected(실패): 비동기 작업이 실패하거나, 오류가 발생한 상태.
let promise = () => { return new Promise((resolve, reject) => { //프로미스 객체는 new Promise로 생성하고 인자로는 executor라는 함수를 인자로 받는다. //excutor 함수는 또 resolve와 reject라는 함수를 인자로 받는다. //만약 서버에서 어떤 데이터를 받아온다고 가정해보자 데이터를 가져오는 함수(주소, function(데이터) { if (데이터) {//데이터 불러오는데 성공했다면 resolve(데이터); } reject(new Error); //실패하면 }); }
- 프로미스가 생성되자 마자, excutor 함수가 실행되기 때문에 조건 분기를 잘 나눠서 프로미스를 생성해야 한다. (서버와 불필요한 통신을 할 가능성이 있기 때문에)
promise() .then((data) => { //then은 같은 프로미스 객체를 리턴한다. //then의 매개변수는 resolve 함수의 인자다. return 해당 데이터로 할 다른 작업들() //여기서의 리턴은 프로미스 객체를 생성할때의 resolve 안에 들어있는 인자라고 생각해도 될 것 같다. //그렇기에 다음 then의 매개변수에 인자로 들어갈 수 있다. } .then((data2) => { //콜백 함수처럼 then을 계속 이어 데이터들을 사용할 수 있다. //data2는 위의 리턴된 함수의 결과값이 들어간다. //단순히 변수가 리턴되었다면 변수가 then의 인자로 간다. return 결과 } .catch((error) => { //reject에 인자가 들어갈 경우 catch를 통해 다룰 수 있다. console.log(error) } .finally(() => { //finally는 성공했건 실패했건 마지막에 무조건 실행된다. })
Promise.all
- 프로미스를 then으로 계속 연결 시킨 경우를 살펴보자. 해당 프로미스에서 작업이 끝나면 다음 then에 있는 작업이 시작된다.
- 만약 이전 프로미스 작업과 then에서 하는 작업이 서로 연관성이 없다면, 굳이 따로따로 할 필요가 있을까.
let plusAllData = () => { return Promise.all([어떤 데이터1을 가져오는 함수, 어떤 데이터2를 가져오는 함수]) //당연하게도 위 함수들은 프로미스 객체를 리턴한다. //위의 인자로 들어간 함수(프로미스 객체)가 갖는 데이터들을 한꺼번에 갖는 프로미스 객체가 리턴된다. .then((allData) => { console.log(allData) } }
1-3. Async & Await
- 위의 프로미스와 작동원리는 같으나, 좀 더 간편하고 동기적으로 보이게 쓰일 수 있는 기능이다.
let AsyncFtn = async () => { //async를 쓰면 함수 자체가 프로미스 객체를 리턴한다. let id = await 어떤 아이디를 가져오는 함수() //물론 이 함수들도 프로미스를 리턴하는 함수다. let password = await 어떤 비밀번호를 가져오는 함수() return `${id}의 비밀번호는 ${password}다.` //?! //AsyncFtn 함수는 return 값을 갖는 프로미스 객체를 리턴한다. }
- await은 해당 함수가 작업을 다 완료할 때까지 기다렸다가 실행된다.
let AsyncFtn = async () => { try { let id = await 어떤 아이디를 가져오는 함수() ... } catch (error) { console.log(error) }
- try ... catch를 통해 에러를 관리할 수 있다.
'취준 > Node.js' 카테고리의 다른 글
[JS] call by value vs call by reference (0) | 2021.11.22 |
---|---|
[JS] Supporting Multiple Constructors in JavaScript (0) | 2021.11.18 |
async await, promise 같이 사용하기 (0) | 2021.06.16 |
callback vs promise vs async await (0) | 2021.06.15 |
[Promise.all] 순서를 보장할까? (0) | 2021.06.07 |