TIL - Promise, async, await

sunn·2022년 1월 26일
0

Promise

비동기 작업 중 서버에서 데이터를 다 받기 전에 화면 랜더링 하는 것을 막기 위해 사용한다.

Promise의 3단계

Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태

Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태

Rejected(실패): 비동기 처리가 실패하거나 오류가 발생한 상태

Pending(대기)

먼저 아래와 같이 new Promise() 메서드를 호출하면 대기(Pending) 상태가 됩니다.

new Promise();

new Promise() 메서드를 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 resolvereject입니다.

new Promise(function(resolve, reject) {
// ...
});

Fulfilled(이행) - 성공

여기서 콜백 함수의 인자 resolve를 아래와 같이 실행하면 이행(Fulfilled) 상태가 됩니다.

new Promise(function(resolve, reject) {
  resolve();
});

---

// resolve가 호출되면 3초 뒤 'OK'를 호출하는 함수
const p = new Promise(resolve, reject) => {
	setTimeOut( () => {
		resolve('OK') // reject(new Error('error..'))
	}, 3000).       // }, 3000)
}                 // reject 호출시 3초 후 'error..'를 반환

p.then(              => p.then(
	function(result) { }     function(result) { }
	function(err) { }     ).catch(
)                          function(err){ }
                        )

그리고 이행 상태가 되면 아래와 같이 then()을 이용하여 처리 결과 값을 받을 수 있습니다.

function getData() {
  return new Promise(function(resolve, reject) {
    var data = 100;
    resolve(data);
  });
}

// resolve()의 결과 값 data를 resolvedData로 받음
getData().then(function(resolvedData) {
  console.log(resolvedData);// 100});

※ 프로미스의 '이행' 상태를 좀 다르게 표현해보면 '완료' 입니다.

Rejected(실패)

new Promise()로 프로미스 객체를 생성하면 콜백 함수 인자로 resolve와 reject를 사용할 수 있다고 했습니다. 여기서 reject를 아래와 같이 호출하면 실패(Rejected) 상태가 됩니다.

new Promise(function(resolve, reject) {
  reject();
});

그리고, 실패 상태가 되면 실패한 이유(실패 처리의 결과 값)를 catch()로 받을 수 있습니다.

function getData() {
  return new Promise(function(resolve, reject) {
    reject(new Error("Request is failed"));
  });
}

// reject()의 결과 값 Error를 err에 받음
getData()
.then()
.catch(function(err) {
  console.log(err); // Error: Request is failed
});

프로미스 코드 - 쉬운 예제

그럼 위에서 배운 내용들을 종합하여 간단한 프로미스 코드를 만들어보겠습니다. 이해하기 쉽게 앞에서 살펴본 ajax 통신 예제 코드에 프로미스를 적용해보겠습니다.

function getData() {
  return new Promise(function(resolve, reject) {
    $.get('url 주소/products/1', function(response) {
      if (response) {
        resolve(response);
      }
      reject(new Error("Request is failed"));
    });
  });
}

// 위 $.get() 호출 결과에 따라 'response' 또는 'Error' 출력
getData().then(function(data) {
  console.log(data);// response 값 출력}).catch(function(err) {
  console.error(err);// Error 출력});

위 코드는 서버에서 제대로 응답을 받아오면 resolve() 메서드를 호출하고, 응답이 없으면 reject() 메서드를 호출하는 예제입니다. 호출된 메서드에 따라 then()이나 catch()로 분기하여 응답 결과 또는 오류를 출력합니다.

Source: 캡틴판교 - 자바스크립트 Promise 쉽게 이해하기 https://joshua1988.github.io/web-development/javascript/promise-for-beginners/#%ED%94%84%EB%A1%9C%EB%AF%B8%EC%8A%A4-%EC%BD%94%EB%93%9C---%EC%89%AC%EC%9A%B4-%EC%98%88%EC%A0%9C


Promise.all() ⇒ 그냥 프로미스 체이닝보다 랜더링 시간 단축 가능 /

하나의 데이터라도 누락되면 어떠한 값도 얻을 수 없다. 따라서 무결점 검사에도 활용 가능

예시)

Promise.all([f1(), f2(), f3()])
.then((res){
	console.log(res)
})

Promise.race() ⇒ 여러 프로미스 중 가장 먼저 완료된 프로미스만을 보여줌 (에러인 경우에도 동일)

사용법은 .all()과 동일

드림코딩엘리

Promise의 세가지 상태에 따른 활용, 개발자와 소비자의 차이를 이해하고 접근

새로운 promise가 생성되면 executor가 자동으로 실행되므로 불필요한 로드가 생길 수 있음

네트워크, 파일 읽기 등의 작업은 비동기환경에서 처리하는 것이 유리

const promise = new Promise((resolve, reject) => {
    // 네트워크, 파일 읽기 등은 비동기적으로 처리하는 것이 유리
    console.log('doing something...')
    setTimeout(() => {
        resolve('sun')
    }, 2000)
});
//    reject(new Error('no network')) => err
// }, 2000)

    // 2. Consumers : then, catch, finally
    // resolve가 호출될 시
promise.then((value) => {
    console.log(value)
})
// reject가 호출될 시 catch로 error를 출력할 수 있음.
.catch(error => {
    console.log(error)
})
.finally(() => console.log('fin'))

// 3. Promise Chaining
const fetchNum = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    }, 1000);
})

fetchNum
    .then(num => num * 
    .then(num => num * 3)
    .then(num => {          // 6
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(num - 1) // 5
            }, 1000);
        })
    })
    .then(num => console.log(num)) // 5

    // 4. Error Handling
const getHen = () => 
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('🐔')
        }, 1000);
    })
const getEgg = hen => 
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(`${hen} => 🥚`)
        }, 1000);
    })
const cook = egg =>
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(`${egg} => 🍳`)
        }, 1000);
    })

getHen()
    .then(getEgg)
    // .catch(error => { 
    //     return '🍗'
    // }) // 만약, getEgg 단계에서 에러 발생 시 🍗 => 🍳가 출력됨
    .then(cook)
    .then(console.log) // 🐔 => 🥚 => 🍳

async & await

// 1. async = function 앞에 붙이면 자동으로 Promise 형태로 return 해줌
async function fetchUser() {
	// doing..
	return 'fin'
}

const user = fetchUser()

// 2. await

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

async function getApple() {
    await delay(1000)
    return '🍎'
}

async function getBanana() {
    await delay(1000)
    return '🍌'
}

function pickFruits() {
    return getApple()
    .then(apple => {
        return getBanana().then(banana => `${apple} + ${banana}`)
    })
}

async function pickFruits() {
    // 병렬적 진행
    const applePromise = getApple()
    const bananaPromise = getBanana()
    const apple = await applePromise()
    const banana = await bananaPromise()
    return `${apple} + ${banana}`
}

pickFruits().then(console.log) // 🍎 + 🍌

// 3. Promise API
function pickAllFruits() {
    return Promise.all([getApple(), getBanana()])
    .then(fruits => fruits.join(' + ')
    )
}
pickAllFruits().then(console.log) // 🍎 + 🍌

타이머 관련 API

setTimeout(callback, millisecond)

일정 시간 후에 함수를 실행

  • arguments: 실행할 callback 함수, callback 함수 실행 전 기다려야 할 시간 (밀리초)
  • return value: 임의의 타이머 ID
setTimeout(function () {
  console.log('1초 후 실행');
}, 1000);
// 123

setInterval(callback, millisecond)

일정 시간의 간격을 가지고 함수를 반복적으로 실행

  • arguments: 실행할 callback 함수, 반복적으로 함수를 실행시키기 위한 시간 간격 (밀리초)
  • return value: 임의의 타이머 ID
setInterval(function () {
  console.log('1초마다 실행');
}, 1000);
// 345

clearInterval(timerId)

반복 실행 중인 타이머를 종료

  • arguments: 타이머 ID
  • return value: 없음
const timer = setInterval(function () {
  console.log('1초마다 실행');
}, 1000);
clearInterval(timer);
// 더 이상 반복 실행되지 않음

(setTimeout에 대응하는 clearTimeout도 있음)

어려워

profile
:-)

0개의 댓글