Notice
Recent Posts
Recent Comments
«   2025/05   »
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 31
Archives
Today
Total
관리 메뉴

Día de Ruru

JavaScript 기본 개념 공부 day5 본문

JS

JavaScript 기본 개념 공부 day5

공대루루 2023. 2. 23. 19:57

동기와 비동기


자바 스크립트엔진은 싱글 스레드로 동작한다. 싱글 스레드로 작업을 수행하는 것의 장점은 프로그래밍의 난이도가 상대적으로 쉽고, 일반적인 상황에서 멀티 스레드로 작업하는 것보다 비용이 적으며 속도가 빠르다는 것이 있다. 단점으로는 연산량이 많거나 구조적으로 시간이 걸리는 작업을 하는 경우, 그 작업이 완료되어야 다른 작업을 수행할 수 있다는 것과 에러에 신경을 더 써야한다는 것이다.

비동기 작업은 싱글스레드의 단점 중 작업이 완료되어야 다른 작업을 수행할 수 있다는 점을 보완해준다. 아래 그림은 비동기 과정의 런타임 요소들이다. 그림이 허접하지만 귀여우니까 괜찮아

왼쪽 위에는 콜스텍 오른쪽 위에는 Web API 가 있고 Web API안에는 DOM,AJAX,Timeout 이 있다. 아래쪽에는 Event Loop 와 Task Queue 가 있다.
비동기 런타임의 요소들

  • Call Stack: 자바스크립트에서 수행해야 할 함수들을 순차적으로 스택에 담아 처리
  • Web API: 웹 브라우저에서 제공하는 API로 AJAX나 Timeout등의 비동기 작업을 실행
  • Task Queue: Callback Queue라고도 하며 Web API에서 넘겨받은 Callback함수를 저장
  • Event Loop: Call Stack이 비어있다면 Task Queue의 작업을 Call Stack으로 옮김
setTimeout(() => console.log('Hello!'),5000);

콜스텍에 비동기 함수인 setTimeout()이 생기고 webAPI 쪽으로 화살표가 되어있다 WebAPI 에서 시작된 화살표는 Task Queue로 연결되어있으며 Task Queue에는 콜백이 생겼다
위의 코드가 실행될 때의 런타임 과정

위의 그림처럼 비동기 함수가 실행되면  콜스텍은 web API에 함수를 처리하라고 요청을 보낸다. Web API는 처리가 완료되면(지정된 시간이 지나면) Task Queue에 콜백함수를 전달한다.Event Loop는 계속 Task Queue와 콜스텍을 확인하면서 콜스텍이 비어있는데 Task Queue가 비어있지 않을 때 콜백함수를 콜스텍에 전달해준다.

프로미스,async/await


Promise 는 비동기로 작업을 실행했을 때 그 작업이 성공했는지 실패했는지를 표준화된 방식으로 처리할 수 있게 해준다. promise를 사용하면 비동기 메스드를 마치 동기 메서드처럼 값을 반환할 수 있다. 미래의 어떤 시점에서 결과를 제공하겠다는 약속을 하는것이다.

let promise = new Promise(function(resolve, reject) {
  // executor 
});
let promise = new Promise((resolve, reject) => {
  // executor 
});

promise는 위의 코드처럼 일반 함수를 넣거나 화살표함수를 넣어서 만들 수 있다. promise는 new로 생성하자마자 바로 실행되며 executor 자리에 필요한 코드를 작성하면 된다. 처리가 끝나면 executor는 처리 성공 여부에 따라 resolve나 reject를 호출한다. 둘 중 하나를 반드시 호출해야 한다!!!

  • resolve(value) — 일이 성공적으로 끝난 경우 그 결과를 나타내는 value와 함께 호출
  • reject(error) — 에러 발생 시 에러 객체를 나타내는 error와 함께 호출

promise의 state는 처음엔 panding이었다가 resolve가 호출되면 fulfilled, reject가 호출되면 rejected로 변하며 result는 처음에는 undefined였다가 resolve가 호출되면 value, reject가 호출되면 error로 변한다.

then, catch, finally

promise 객체는 executor와 결과나 에러를 받을 소비함수를 이어주는 역활을 한다. 소비 함수는 .then .catch .finally 메서드를 사용해서 등록된다.

1. then : promise의 기본 메서드이다.

promise에서 실행이 성공했을 때 resolve에 '완료!' 라는 문자를 넣어주는데 .then은 그 value를 가져와서 사용할 수 있다.

let promise = new Promise(resolve => {
  setTimeout(() => resolve("완료!"), 1000);
});

promise.then(alert);

2. catch : 에러가 발생한 경우만 다루고 싶을 때 사용한다.

let promise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("에러 발생!")), 1000);
});

promise.catch(alert);

 .catch(f)는 promise.then(null, f)과 문법이 간결하다는 점만 빼고 똑같이 작동한다.

3. finally : 성공 여부와 별개로 항상 마지막에 실행시키고 싶을 때 사용한다.

fianlly 핸들러는 성공 여부와 상관없이 실행되기 때문에 인수가 없으며 결과값을 다음 핸들러에 전달해준다.

new Promise((resolve, reject) => {
  setTimeout(() => resolve("결과"), 2000)
})
  .finally(() => alert("프라미스가 준비되었습니다."))
  .then(result => alert(result));

위의 결과 .then에서 result를 받아와서 사용한다. finally가 작동하면서 자신이 받은 result를 then에게 전달해준것이다.

promise 체이닝

프라미스 체이닝이 가능한 이유는 promise.then을 호출하면 프라미스가 반환되기 때문이다. 반환된 프라미스엔 당연히 .then을 호출할 수 있다.

new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 1000);
  
}).then(function(result) {
  console.log(result); // 1
  return result * 2;

}).then(function(result) {
  console.log(result); // 2
  return result * 2;

위와 같이 체이닝을 했을 때 첫 번째 then은 resolve의 result를 받고 두 번째 then은 첫번째 then에서 return 된 결과 값을 받아서 사용한다. 그러므로 두번 째 return은 4가 된다!!

Promise API

1. Promise.all : 배열로 받은 여러개의 promise의 결과값을 담은 새로운 promise를 만든다.

Promise.all([
  new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
  new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
  new Promise(resolve => setTimeout(() => resolve(3), 1000))  // 3
]).then(console.log);

위 코드를 실행하면 1,2,3이 출력된다. 실행 속도가 가장 느린 promise 가 가장 앞에 있지만 배열에는 순서대로 출력된다.

2. Promise.allSettled : Promise.all의 단점을 보완한 API

Primise.all은 배열안에 있는 promise들 중에서 하나라도 에러나 발생하면 다른 promise들은 무시되고 promise.all은 바로 거부된다. 하지만 배열 안에 있는 promise 중에 하나가 에러가 발생하더라도 다른 pomise 들이 필요한 경우가 생길 수 있다. 그럴 때 사용하는 것이 promise.allSettled 이다.

3. Promise.race : 배열로 받은 여러개의 promise 중 가장 먼저 처리되는 promise를 반환한다.

Promise.race([
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error("에러 발생!")), 2000)),
  new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).then(console.log);

위 코드의 경우 배열안에 있는 promise들 중 첫번째 promise가 가장 빠르기 때문에 1이 출력된다.

async 와 await

1. async : function 앞에 async를 붙이면 해당 함수는 promise를 반환한다.

async는 평범한 함수를 promise를 리턴하는 비동기 함수로 만들어준다. async가 붙어있는 함수 내부에서는 await를 사용할 수 있다.

async function fetchUser(){
    return 'ryu';
}

const user = fetchUser()
user.then(console.log)

2. await

promise가 처리될 때까지 함수 실행을 기다리게 하고 promise가 처리되면 그 결과와 함께 실행이 재개된다. 그러므로 비동기 작업이지만 동기적으로 동작하는 것 처럼 보이게 한다. await는 항상 async 함수 내부에서만 사용할 수 있다.

function delay(ms){
    return new Promise (resolve => setTimeout(resolve,ms));
}

async function getApple(){
    await delay(2000); //await 다음에 쓰여진 함수가 완료될 때까지 기다려준다
    return 'apple'
}

위 코드의 경우 getApple()이 실행될 때 delay()에서 기다렸다가 apple을 return한다.

'JS' 카테고리의 다른 글

JavaScript 기본 개념 공부 - Class  (0) 2023.04.09
JavaScript 기본 개념 공부 day6  (0) 2023.02.26
JavaScript 기본 개념 공부 day4  (0) 2023.02.23
JavaScript 기본 개념 공부 day3  (0) 2023.02.22
JavaScript 기본 개념 공부 day2(3)  (0) 2023.02.15
Comments