동기/비동기, Callback, Promise, Async Await

김종현·2023년 3월 16일
0

Js

목록 보기
10/16

동기(synchronous)/비동기(asynchronous) 동작 원리

  1. 동기
    -코드 실행 순서로 call stack에 실행 함수가 쌓인다(push)
    -마지막에 쌓인 것 부터 함수가 실행된다.(LIFO)
    -실행이 된 함수는 call satack에서 제거(pop)된다.

  2. 비동기
    -Call Stack에서 비동기 함수가 호출되면 Call Stack에 먼저 쌓였다가 Web API(혹은 백그라운드라고도 한다)로 이동한 후 해당 함수가 등록되고 Call Stack에서 사라진다.
    -Web API(백그라운드)에서 비동기 함수의 이벤트가 발생하면, 해당 콜백 함수는 Callback Queue에 push(이동) 된다.
    -이제 Call Stack이 비어있는지 이벤트 루프(Event Loop)가 확인을 하는데 만약 비어있으면, Call Stack에 Callback Queue에 있는 콜백 함수를 넘겨준다.(push)
    -Call Stack에 들어온 함수는 실행이 되고 실행이 끝나면 Call Stack에서 사라진다.

  • cb, Promise, Async await 까지 비동기 구현 3가지.

콜백함수

-다른 함수의 파라미터로 들어가 쓰이는 함수.
-에러와 결과를 같이 전달하는 것이 표준, 보통 첫 인자로 에러를 둚. (getUsers((err, users)=>{...});


//비동기 함수 : 2초 뒤에 Elice라는 이름을 인자로 받은 콜백함수의 인자로 넘겨준다.
function getName(cb) {
    setTimeout(() => {
        cb("Elice");
    }, 2000);
}
//앞선 함수를 실행하려면 다음과 같이 getName 함수에 콜백함수를 넣어서 사용
getName((name) => {
    console.log(name);
})

setTimeout

-개념상 파라미터로 받는 시간(최소 대기 시간, 무조건 지켜지진 않음)만큼 대기 후 작업을 수행하나 컴퓨터 성능이나 setTimeout 뒤의 코드에 따라 실제로 늦게 불려질 수 있다.

function next() {
    console.log('do something');
    setTimeout(next2, 1000);
}

function next2() {
    console.log('and do another thing');
    setTimeout(next3, 2000);
}

function next3() {
    console.log('and then finally');
}

setTimeout(next, 1500);

"do something"
"and do another thing"
"an.d then finally"
console.log('hello');
setTimeout(() => {console.log('finished'); }, 0);
console.log('ok');

"hello"
"ok"
"finished"

hello 출력 - cb 함수 web api로 넘어가 계산 - ok 출력 - fininshed 출력

Promise

-각기 다른 콜백 방식들을 표준화, resolve와 reject를 써서 인터페이스를 하나로 합치기 위한 수단

-비동기 처리의 순서를 표현할 수 있다(비동기 작업을 표현하는 Js 객체)
-for/if문으로는 처리가 안되는 작업에 promise를 쓴다.
-매개변수 resolve, reject가 존재. Promise에 의해 결정되는 값을 받아 then으로 넘김

  • 비동기 작업이 맞이할 미래의 완료 or 실패와 그 결과 값.

-비동기 작업의 진행, 성공, 실패 상태를 표현.

  • new Promise(...) 혹은 fetch API 처럼 promise를 반환하는 비동기 API를 사용.
  • 비동기 작업이 실행될 경우 Pending 상태(진행상태)가 되고 여기서 성공-fulfilled/resolved 혹은 실패-rejected를 표현할 수 있다.
  • 성공과 실패를 통틀어 settled라고 한다.(작업 종료)
  • 이처럼 promise 내부에는 상태를 나타내는 flag가 있다.
  • 성공시 .then(), 실패시 .catch() 메서드가 호출된다. 즉 reject는 catch에 등록된 callback 실행, resolve는 then에 등록된 callback 실행
  • then 메서드는 성공/실패 cb를 넣을 수 있는데 실패 cb는 catch 대신 호출이 되고 생략이 가능하다. catch 또한 실패 cb를 가진다.

promise api는 비동기 api중 하나

-Job queue(or microtask queue, task queue보다 우선 순위가 높다)를 사용

  • 실행 결과를 보면 프로미스가 타임아웃보다 앞선다.

https://joshua1988.github.io/web-development/javascript/promise-for-beginners/

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve

new Promise(function (resolve, reject) {
  //무언가 하고 성공시 resolve, 실패시 reject
  //성공하면 콜백함수 resolve() 실행, 괄호 안의 내용 호출
  const payload = {message:'done!'};
  resolve(payload);
  //실패하면 콜백함수 reject() 실행
  const error = new Error('failed!');
  reject(error);
});

resolve나 reject 중 하나를 넣고 then으로 처리를 받아서 해결.

const task = new Promise(function (resolve, reject) {
    resolve('hi'); //성공시 이것

    // reject(new Error('failed!')); 실패시 이것
});

task.then(
    function handleSuccess(data) {
        console.log(data);
    },
    function handleError(error) {
        console.log(error);
    }
);
//then은 promise된 콜백함수 사용에 필수, 성공/실패를 위한 값을 각각 받음.
//값을 받아서 다음을 처리해달라는 뜻.

// or

task.then(function handleSuccess(data) {
    console.log(data);
}).catch(function handleError(error) {
    console.log(error);
});


// 쉽게 쓰기
task.then(data => { console.log(data); })
    .catch(error => { console.log(error); });
//reject는 catch로 연결
//	.finallay( ()=> {console.log('hi');}); finally 쓸 수 있음
//promise를 에러처리할 떄도 쓸 수 있다

callback이 여러개 쓰이는데 이것을 그냥 then으로 값을 바로 받아서 씀.

//참고용, 화살표 함수를 활용한 함수 함축
const wait = (ms) => {
  return new Promise((resolve, reject) => {
    setTimeout( ()=> {
      resolve()
    }, ms)
  });
};
//위 코드는 아래와 같음.

const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
function doSomething(num) {
    return new Promise(resolve => {
        console.log('do something');

        resolve(num + 1);
    });
}

function doAnother(num) {
    return new Promise(resolve => {
        console.log('do another');

        resolve(num + 10);
    });
}

doSomething(100)
.then(doAnother)
.then(num => {
  console.log('num', num);
});
//then 을 통해 값을 받아 넘기면서 chanining 가능

//do something
//do another
// num 111

Promise 생성자 : Producer; new Promise

-Promise 생성자는 특정 작업을 Promise화 시켜주는 것일 뿐 그 이상 그 이하도 아니다.
setTimeout과 같은 cb만 지원하는 메소드를 promise화할 때 정도만 사용.

let promise = new Promise((resolve, reject)=>{
  if(Math.random() <0.5) {
    return reject('실패')
  }
  resolve(10)
})

-랜덤 함수를 사용 그 값이 0.5 밑이면 reject 호출, "실패" 반환
-값이 0.5 밑이 아니라면 resolve를 호출, 10을 반환

new Promise (callback;executor)

-cb 함수는 (resolve, reject) 두 콜백함수를 인자로 받아 각각 성공, 실패시 호출
-내부에서 직접 호출을 함으로써 성공/실패를 조작 가능.

★new Promise가 생성되면 executor는 바로 실행되므로 불필요한 소요가 발생할 수 있음!

//실 사용 예시
//생성
//findUserByUsername, findAddressByUserId 함수는 모두 Promise를 리턴
//findUserByUsername API 함수를 이용하여, value 값을 이용해 유저를 검색
export const findUserByUsername = (username) =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      const foundUser = userData.find((user) => user.username === username);
      if (foundUser) {
        return resolve(foundUser);
      }
      reject(new Error("유저를 찾지 못했습니다."));
    }, 300);
  });

//findAddressByUserId API 함수를 이용하여, 찾은 user의 id를 이용해 주소를 검색
export const findAddressByUserId = (userId) =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      const foundAddress = addressData.find(
        (address) => address.userId === userId
      );

      if (foundAddress) {
        return resolve(foundAddress);
      }
      reject(new Error("주소를 찾지 못했습니다."));
    }, 300);
  });


//사용
//searchAddress는 address 객체를 반환하는 Promise를 리턴
//catch를 이용해, 에러 발생 시 error에 error.message를 저장
  function searchAddress() {

    return findUserByUsername(value)
    .then(user => findAddressByUserId(user.id))
    .catch(e => {
        error = e.message
    })
  }

(중요) Promise를 제공하지 않는 비동기 함수(callback 기반 함수)를 Promise 함수로 변경하는 방법

db.getU


function getUsersPromise(params) {
  return new Promise( (resolve, reject) =>{
    getUsers(params, (err, users) =>{
      if (err) {
        reject(err);
        return;
      }
      resolve(users);
    });
  });
}
//getUsers의 실행이 완료되면 err, users를 반환.
//콜백함수의 결과 에러는 reject로 users는 resolve로 전달됨.
// API콜 캐싱 예시
const cache = new Map();

function getSomethingFromRemote(url) {
  if (cache.has(url)) {
    return Promise.resolve(cache.get(url)); // fetch가 promise를 리턴하기 때문에 여기서도 강제로 promise화를 해줘야한다. 함수는 항상 통일된 리턴 타입을 가져야한다. 가령, 하나의 리턴문에서 Promise를 리턴한다면 다른 리턴문들도 Promise를 러턴해야한다.
  }
  if (url !== undefined && url !== null && url.length > 0) {
    return fetch(url)
      .then((response) => response.json())
      .then((result) => {
        cache.set(url, result);
        return result;
      }); // promise를 리턴
  }
  return Promise.reject(new Error("URL이 있어야합니다."));
}

// promise flattening 예시
fetch("https://ipapi.co/json")
  // 아래의 response.json은 promise를 리턴하지만 promise가 resolve되면 다음 then으로 넘어간다.
  .then((response) => response.json())
  // 아래의 json.city는 string값(promise X)
  // then에게 넘겨주는 함수는 primitive 또는 promise를 리턴할 수 있다. 결과는 같다.
  // .then((json) => Promise.resolve(json.city))
  .then((json) => json.city)
  .then((city) => console.log(city));

Promise 메서드 : Consumer; then, catch, finally


-then 메서드에 성공시 실행할 콜백 함수를 인자로 넘긴다

  • then(cb1, cb2) 형태로 cb1은 성공, cb2는 실패 메서드를 인자로 넘길 수 있다.
  • 내부적으로 Promise를 반환한다.
    -catch 메서드엔 실패시 실행할 콜백 함수를 인자로 넘긴다
  • then/catch가 항상 promise에 대한 정보를 반환하진 않는다. 넘길 수 있는 값은 다양하게 쓸 수 있다

-finally 메서드는 성공/실패 여부에 상관 없이 실행할 콜백 함수를 인자로 넘긴다.(settled 시 항상 호출)

1. Producer
const promise = new Promise( (resolve, reject) => {
  console.log('doing sth'); //바로 실행됨
  setTimeout( ()=> {
    resolve('kim');
    //reject(new Error('no network');
    //Uncaught (in promise) Error : no network at promise.js:~~
  }, 2000);
});

2. Consumer : then, catch, finally
  promise
  	.then(value => {
    //promise 정상 실행시 cb함수 resolve가 넘겨준 값을 value라는 파라미터로 받아옴
    console.log(value); 
    //kim
  })
	.catch(error => {
    //promise 실행 실패시 cb함수 reject가 넘겨준 값을 error라는 파라미터로 받아옴
    console.log(error); 
    //Error : no network at promise.js:~~
  });
	.finally( () => {console.log('finally');
    //앞의 then/catch와 상관없이 finally 무조건 출력
  }); 

Promise chaining

const fetchNumber = new Promise( (resolve, reject) =>{
  setTimeout ( ()=> resolve(1), 1000);
  //1초 있다가 숫자1을 반환
});

fetchNumber
.then(num => num*2) //2
.then(num => num*3) //6
.then(num => {
  return new Promise( (resolve, reject) => {
    setTimeout( ()=> resolve(num - 1), 1000);
    //5
  });
})
.then(num => console.log(num));
//5
//출력까지 걸리는 시간 2초
//이와 같이 비동기적인 놈들을 묶어서 처리할 수 있음
promise
.then(data => {
  return fetchUser(data)
})
.then(user => {
  sonole.log('User : ', user)
})
.catch(e => {
  conosle.log("실패: ",e)
});

-then/catch 메서드가 또 다른 promise를 리턴하여 비동기 코드에 순서를 부여한다.
-함수를 호출한 주체가 함수를 끝낸 뒤 자기 자신을 리턴하도록 구현한다.

  • ex) array.map().sort().join(); array를 받아 map이 다시 배열을 반환하기 때문에 체이닝이 일어난다.
  • Promise의 체이닝은 then이 promise를 반환하기 때문에 일어난다.

-then 체인을 이용해 비동기 처리 순서를 강제할 수도 있다

-new Promise를 생성하면 생성자는 내부적으로 return this라는 코드가 생략이 되어있다. then 또한 마찬가지이다. 이렇게 자기 자신을 return 하는 함수들이 있기 때문에 그 객체에 있는 .then/.catch 메서드가 연달아 호출될 수 있다.

  • ex)위 코드에서 then에 data대신 number 10을 주면 그 다음 then은 10을 받는다. 그런데 cb(fetchUser)가 promise를 반환하는 함수라면 그 다음 then이 호출되기 전에 선행하는 promise가 끝날 때 까지 기다리게 된다. (즉 promise2가 생겨나면서 promise1의 순서를 기다림) 그렇기 때문에 비동기 코드에 순서가 생긴다.

Promise.resolve, Promise.reject : 정적 메소드

Promise를 반환하는 함수를 만들어 호출할 필요 없이 바로 성공/실패 Promise를 호출이 가능함

-Promise.resolve() : 성공한 Promise를 바로 반환
-Promise.reject() : 실패한 Promise를 바로 반환
-인위적으로 Promise 메서드 체인 생성 가능
-비동기 코드로 진행해야 하는 상황 등에 유용하게 사용 가능

Promise.all : 정적 메소드, Promise의 병렬 실행.

Promise '배열'을 받아 모두 성공하거나 하나라도 실패할 때까지 기다려 결과 반환

-Promise의 '배열'을 받아 모두 성공 시 각 Promise의 resolved 값을 배열로 반환
-하나의 Promise라도 실패시 가장 먼저 실패한 Promise의 실패 이유를 반환
-받는 배열이 promise가 아니라 일반 데이터일 수도 있음

async function sync() {
  const r1 = await promise1();
  const r2 = await promise2();
  console.log(r1, r2);
}
---
async function parallel(){
  const [r1, r2] = await Promise.all([
    promise1(),
    promise2(),
    ]);
    console.log(r1,r2);
}

-promise1과 promise2는 각각 1초, 2초가 소요되는 비동기 함수.
-위의 함수에서는 3초의 시간이 소요.
-아래의 함수에서는 2초의 시간이 소요.

all의 세부적인 error 캐치를 위해서는

Promise.all([fetch().catch(err), fetch().catch(err), fetch().catch(err)])
try{
}
catch{
}

콜백 함수를 Promise로 바꾸기

function doSomething(callback) {
    console.log('[doSomething] I am doing something');
    console.log('[doSomething] done!');

    const payload = {
        done: true,
    };

    callback(payload);
}

function doAnother(payload, callback) {
    console.log('[doAnother] do something another task');
    console.log('[doAnother] ok done!');

    payload.flag = true;

    callback(payload);
}

function main(callback) {
    doSomething(function(payload) {
        if (payload.done) {
            doAnother(payload, function(payload) {
                console.log('looks all good!');

                callback(payload);
            });
        } else {
            callback(payload);
        }
    });
}

main((payload) => {
    console.log('all finished -', payload);
});

console.log('======================');

function doSomething2() {
    return new Promise(resolve => {
        console.log('[doSomething] I am doing something');
        console.log('[doSomething] done!');

        const payload = {
            done: true,
        };

        resolve(payload);
    });
}

function doAnother2(payload) {
    console.log('[doAnother] do something another task');
    console.log('[doAnother] ok done!');

    payload.flag = true;

    // return new Promise(resolve => resolve(payload));
    return payload;
}

function main2() {
    const result = doSomething2()
        .then(payload => {
            if (payload.done) {
                return doAnother2(payload);
            } else {
                return payload;
            }
        })
        .then(payload => {
            console.log('looks all good!');

            // return new Promise(resolve => resolve(payload));
            return payload;
        });

    return result;
}

main2().then((payload) => {
    console.log('all finished -', payload);
});

setTimeout을 promise화

function tick(duration) {
    return new Promise(resolve => {
        setTimeout(resolve, duration);
    });
}

function test2() {
    console.log('hello, wait 1s');

    tick(1000)
        .then(() => {
            console.log('now wait 500ms');
        })
        .then(() => tick(500))
        .then(() => {
            console.log('ok wait 3s for the last');
        })
        .then(() => tick(3000))
        .then(() => {
            console.log('done!');
        });
}
test2();


//test2와 test는 같은 값 반환
async function test() {
    console.log('hello, wait 1s');
    await tick(1000);

    console.log('now wait 500ms');
    await tick(500);

    console.log('ok wait 3s for the last');
    await tick(3000);

    console.log('done!');
}

test();

Async await

-Promise를 활용한 비동기 코드를 간결하게 만들어주는 문법.
-async 함수와 await 키워드를 이용. await는 반드시 async 함수 안에서만 사용해야 한다.
-async로 선언된 함수는 반드시 Promise를 리턴한다.(return new Promise를 갖는다)
-모든 promise를 async/awiat로 표현할 수는 없다.

db.getUsers((err,users) =>{
  if(err){
    ...
    return;
  }
  async1(users, (r1) => {
    async2(r1, (r2) => {
      async3(r2, (r3)=>{
        ...
      });
    });
  });
});
//위 코드는 async 1, 2, 3을 동기적으로 실행해야 할 때 나오는 코드, 콜백 지옥.
  
  async function doSomething() =>{
    const r1 = await promise1();
    const r2 = await promise2(r1);
    const r3 = await promise3(r1, r2);
    //앞선 결과를 다음 함수에 간단하게 제공.
    //이렇게 순차적이지 않은 promise의 순서를 async는 간결하게 표현 가능.
    ...
    return r3;
  });
  
  doSomething().then(r3 => {
    console.log(r3)
  });

-async 함수 내에서 promise 함수의 결과는 await 으로 받을 수 있다.
-await한 promise 함수가 완료될 때 까지 다음 라인으로 넘어가지 않는다.
-순차적 프로그래밍처럼 작성 가능하다.
-async 함수는 Promise를 반환한다.

Promise와의 비교

1)

function doSomething(num) {
    return new Promise(resolve => {
        console.log('do something');
        resolve(num + 1);
    });
}
function doAnother(num) {
    return new Promise(resolve => {
        console.log('do another');
        resolve(num + 10);
    });
}
function main() {
    doSomething(0)
        .then(doSomething)
        .then(doSomething)
        .then(doSomething)
        .then(doSomething)
        .then(doAnother)
        .then(num => {
            console.log('num', num);
        });
}

//async를 통해 다음과 같이 간결하게 쓸 수 있음
async function main2() {
  //- async 함수는 function 키워드 앞에 async를 붙여 만든다
    let num = await doSomething(0);
  //- async 함수 내부에서 await 키워드를 사용한다.
    num = await doSomething(num);
  //- await 키워드는 then 메서드 체인을 연결한 것처럼 순서대로 동작한다.
  //따라서 비동기 코드에 쉽게 순서를 부여한다.
    num = await doSomething(num);
    num = await doAnother(num);
  //- await는 resolve/reject처럼 데이터를 받을 때 까지 기다렸다가 실행한다.
  //즉, 바로 실행되지 않는다.
    console.log('num', num);
}
  • async 함수는 동기적으로 보이지만 비동기적으로 실행된다. 단, 내부에서 await 키워드가 쓰이지 않았을 경우엔 Promise.resolve()로 처리된다.
  • 또한 await 키워드는 프로미스를 리턴하지 않는 함수라도 사용할 수 있다. 단, 이 경우 리턴한 데이터는 Promise.resolve()로 감싸진다.

2)

//Promise
function p() {
return new Promise((resolve, reject) => {
resolve('hello');
// or reject(new Error('error');
});
}
p().then((n) => console.log(n)); //hello


//async await
async function p2(){ 
	return 'hello';
}
p2().then((n) => console.log(n)); //hello
  • await를 반드시 사용할 필요는 없다.
  • async에도 then 사용이 가능.
  • 함수에 async 만 붙이면 자동으로 promise 객체로 인식되고, return 값은 resolve() 값과 동일.

await에 의한 값 반환

function p() {
return new Promise((resolve, reject) => {
let userName = getUserName("asdasd");
  //서버에서 비동기적으로 받아오는 함수라는 가정
console.log('userName');//undefined출력. 이유는 데이터를 받기 전에 코드가 실행돼서.
  //resolve('userName'); 
  // 값 나옴. resolve로 값을 기다려서 받기때문.
});
}
p().then((n) => console.log(n));


async function p2(){
  let userName = await getUserName("avdffds");
  //await을 써주면 값을 받아올 때 까지 기다려줌.
  
  console.log(userNAme); // 값 나옴, await로 값을 기다려서.
}

에러 처리

https://www.youtube.com/watch?v=JB_yU6Oe2eE&list=WL&index=18&t=728s

1) promise의 오류 처리

function fetchData1(){
  return request()
  .then( (res) => res.requestData)
  .catch(error =>{console.log(error)})
}
  • promise를 리턴하는 함수의 경우 에러 발생시 catch를 통해 처리한다.
  • catch 메서드를 사용하지 않는다면 async 함수에서 try-catch 구문을 이용하여 에러를 처리한다.

2)async의 오류 처리

asnyc function async func(){
try {
    let data1 = await fetchData1()
    return fetchData2(data1)
  } catch (e) {
    console.log("error: ", e)
  }
}
  • try-catch 구문으로 async/await 형태 비동기 코드 에러 처리가 가능하다.
  • catch 절의 e는 promise의 catch 메서드가 받는 반환 값과 동일하다.
async function asyncFunc() {
  try {
    let data1 = await fetchData1()
    return userName;
  } catch (e) {
    console.log("Name error: ", e)
  }
  try {
    let data2 = await fetchData2()
    return userAddress;
  } catch (e) {
    console.log("Address error: ", e)
  }
}

-await으로 Promise 함수를 실행하면 Promise에서 reject 된 에러는 throw가 되기 때문에 try, catch 구문을 사용하여 오류를 처리할 수 있다.

  • 만약 fetchData1,2에 대해서 각 기능에 대한 오류 발생 처리를 세분화 하고 싶다면 이렇게 쓸 수 있다.

cb, promise, async 정리

//비동기 함수 : 2초 뒤에 Elice라는 이름을 인자로 받은 콜백함수의 인자로 넘겨준다.
function getName(cb) {
    setTimeout(() => {
        cb("Elice");
    }, 2000);
}
//앞선 함수를 실행하려면 다음과 같이 getName 함수에 콜백함수를 넣어서 사용
getName((name) => {
    console.log(name);
})
//~ 콜백함수 3개를 사용 할 경우
function getName(cb) {
    setTimeout(() => {
        cb("Elice");
    }, 2000);
}

function getAge(cb) {
    setTimeout(() => {
        cb(6);
    }, 2000);
}

function getAddress(cb) {
    setTimeout(() => {
        cb("Seoul");
    }, 2000);
//c콜백 함수를 반복, 비동기 함수 3개, 2초씩 걸리므로 6초 뒤에 log가 나옴.(콜백지옥)
getName((name) => {
    getAge((age) => {
        getAddress((address) => {
            console.log(name, age, address)
        })
    })
}) 
  //// Promise ////
//Promise를 사용하여 콜백 지옥을 해결하기. 아래의 각 함수는 Promise 객체를 리턴.
function getName() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("Elice");
        }, 2000);
    })
}

function getAge() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(6);
        }, 2000);
    })
}

function getAddress() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("Seoul");
        }, 2000);
    })
}  
//하지만 이렇게 사용하면 정보를 하나의 함수에서 제어하기 힘듦.
getName().then((res) => {
    console.log(res);
})

getAge().then((res) => {
    console.log(res);
})

getAddress().then((res) => {
    console.log(res);
})
//따라서 promise.all은 첫번째 인자에 배열을 받는데 그 배열의 원소는 모두 프로미스 객체.
//getName, getAge, getAddress 함수는 모두 promise객체를 반환하기 때문에 Promise.all에서 사용가능하며 병렬적으로 배열의 원소에 속하는 모든 promise를 동시 실행.
//결과 적으로 2초 후에 log를 한 번에 출력. 콜백함수로는 불가능한 작업임.
Promise
    .all([getName(), getAge(), getAddress()])
    .then((res) => {
        const [name, age, address] = res;
        console.log(name, age, address)
    })
  
	//// Async Await ////
//즉시실행 함수 형태에 async 화살표 함수를 이용해 작성하여 프로미스를 더 간단하게 사용.
//await 키워드에서 프로미스가 resolve 될 때까지 기다린 후 다음 순서로 넘어가므로 6초 후에 log출력.
(async () => {
    const name = await getName();
    const age = await getAge();
    const address = await getAddress();

    console.log(name, age, address);
})();
  

-Promise와 async/await는 효과적으로 사용될 수 있는 상황이 다르기 때문에
두 방법 모두 잘 알고 있어야한다. 메소드 체이닝이 많이 사용되는 코드에서는 Promise가 코드에 일관성을 지켜서 더 깔끔하게 보일 수 있고, 개별 함수를 호출하여 값을 받아오는 경우에는 asyne/await이 효과적이다.

-cb 지옥은 promise chaining으로 해결, promise 지옥은 async-await으로 해결하면 된다.

profile
나는 나의 섬이다.

0개의 댓글