[The Modern JavaScript] The JavaScript language - Promises, async/await

둡둡·2023년 1월 5일
0

Modern-JavaScript

목록 보기
9/10

Callbacks

  • 여러 함수를 사용하면 비동기(asynchronous) 동작을 스케줄링 할 수 있음
    • 스크립트나 모듈 로딩, setTimeout 등
  • 콜백(callback) 함수 : 현재 함수가 끝난 후 나중에 호출할 함수를 추가, 대부분 익명 함수
    • 콜백 기반(callback-based) 비동기 프로그래밍

Callback in callback

  • 중첩 콜백을 통해 로딩 순서를 조절할 수 있음
  • 동작이 많은 경우에는 권장하지 않음

Handling errors

loadScript('script.js', function(error, script){
  if (error) {
    // 에러 발생 시 처리
  } else {
    // 스크립트 로딩이 성공했을 시 처리
  }
});
  • 오류 우선 콜백(error-first-callback)
    • 첫 번째 인수를 에러로 설정하여 에러 발생 시 호출
    • 원하는 동작이 성공한 경우 callback 호출

Pyramid of Doom

  • 중첩 코드가 깊어지면 콜백 지옥(callback hell) 또는 멸망의 피라미드(pyramide of dooom)
  • 비동기 동작이 많은 경우 각 동작을 독립적으로 분리하는 것이 필요

Promise

let promise = new Promise(function(resolve, reject) {
  // executor 실행자, 실행함수
  // state : "pending"
  // result : undefined
});
  • resolve(value) : 성공적으로 끝난 경우 결과를 나타내는 value와 함께 호출
    • state : "fulfilled"
    • result : value
  • reject(error) : 에러 발생 시 에러 객체를 나타내는 error와 함께 호출
    • state : "rejected"
    • result : error
  • executor는 resolve 또는 reject 중 하나를 반드시 호출해야 함
    • 처리된(settled) 프라미스에 다시 호출하는 것은 무시됨

Consumers: then, catch, finally

then

promise.then(
  function(result) { /* 결과 내용 */},
  function(error) {/* 에러 내용 */}
)
  • error 생략 가능
    • promise.then(실행 내용)

catch

  • 에러가 발생한 경우만 다루는 경우
    • .then(null, errorHandlingFunction) : 첫 번째 인수를 null로 전달
    • .catch(errorHandlingFunction)

finally

  • 프라미스 처리 후 성공/에러 여부와 상관 없이 항상 실행되는 절

Example: loadScript

function loadScript(src) {
  return new Promise(function(resolve, reject) {
    let script = document.createElement('script');
    script.src = src;
    
    script.onload = () => resolve(script);
    script.onerror = () => reject(new Error(`${src}를 불러오는 도중에 에러가 발생했습니다.`));
    
    document.head.append(script);
  });
}

let promise = loadScript("/*.js");

// 첫 번째 호출
promise.then(
  script => alert("success");
  error => alert("error");
)

// 두 번째 호출
promise.then( scirpt => alert("other handler"));
  • 원하는 만큼 .then 호출
  • 코드의 흐름이 자연스러움

Promises chaining

new Promise(function(resolve, reject){

  setTimeout(() => resolve(1), 1000);

}).then(function(result){
  
  alert(result); // 1
  return result++; 
  
}).then(function(result){

  alert(result); // 2
  return result++; // 3

});
  • 1초 후 처음 프라미스가 수행됨
  • 반환 값을 전달 받고, 첫 번째 .then 수행
  • 다시 반환 값을 전달 받고, 두 번째 .then 수행

Returning promises

}).then(function(result) {

  alert(result); // 1

  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(result++), 1000); // 2
  });
});
  • 핸들러 (.then) 안에서 프라미스를 반환하여 비동기 작업 체닝 가능

Error handling with promises

  • .catch : 프라미스에서 발생한 모든 에러를 처리함
    • 에러를 처리하려는 위치가 중요
  • unhandledrejection : 처리되지 않은 에러를 추적하고, 사용자에게 문제 상황을 알리는 이벤트 핸들러

Promise API

Promise.all

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(alert); // return [1,2,3]
  • 요소 전체가 프라미스인 배열을 받아 수행하고, 모두 처리된 결과 값을 담은 배열을 새로운 프라미스의 result로 반환
  • 하나라도 에러가 발생하면 즉시 중단되고 다른 프라미스는 모두 무시됨

Promise.allSettled

  • 모든 프라미스가 처리될 때까지 대기
  • 여러 요청 중 하나가 실패해도 다른 결과는 유지

Promise.race

  • Promise.all과 비슷하지만, 가장 먼저 처리되는 결과를 반환 후 다른 프라미스의 결과 또는 에러는 무시됨

Promise.resolve/.reject

  • .resolve(value) : 결과 값이 value인 이행 상태 프라미스 생성
  • .reject(error) : 결과 값이 error인 거부 상태 프라미스 생성

Async/await

async function func() {
  
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("완료"), 1000)
  });
  
  let result = await promise;
  alert(result); 
}

func();
  • async
    • 항상 프라미스 또는 이행된 프라미스 반환
    • 함수 안에서 await 사용 가능
  • await
    • async 함수 안에서만 동작 (일반 함수에는 불가)
    • 프라미스가 처리될 때까지 기다린 후 함수 실행

"Promises, async/await", by Ilya Kantor, 2007-2023, https://javascript.info/async

profile
괴발개발라이프

0개의 댓글