[모던 JavaScript] Promise

sunny·2022년 6월 20일
0

JavaScript

목록 보기
6/7

Promise

Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타낸다.

사용 이유 ❓

비동기적 처리를 할 때 자바스크립트에서는 콜백 방식으로 처리를 많이 한다.
오래 걸리는 작업을 web api, 노드 api를 통해 맡기고 그 결과가 돌아왔을 때 비로소 어떤 작업을 해야 한다는 것을 콜백으로 명시한다.
👉 그렇게 짜게 되면 Callback Hell 😥 (활모양 형태의 코드)
Callback Hell 문제❓ 가독성 문제, 실수할 가능성 ⬆

💡 그렇기 때문에 promiseasync/await 방식으로 해결 💡

Promise는 상태 그래프를 가진다.

어떤 일이 일어날 때마다 오른쪽으로 쭉쭉 간다❗

Promise는 다음 중 하나의 상태를 가진다.

  • 대기(pending): 이행하거나 거부되지 않은 초기 상태.
  • 이행(fulfilled): 연산이 성공적으로 완료됨.
  • 거부(rejected): 연산이 실패함.

코드 설명1

new Promise((resolve, reject) => {
  console.log('Inside promise')
  resolve('First resolve')
}).then((value) => { // 여기서 value는 resolve한 값! (First resolve)
  console.log('Inside first then')
  console.log('value', value)
})

❗ 실행 결과 ❗

  • Promise는 new Promise라는 생성자를 통해서 만들 수 있다.
  • 안에 callback을 넣어주는데, 두 개의 인자를 받는다. 👉 (resolve, reject)
  • resolve가 이루어지고 나면 프로미스는 그 다음 단계로 진행 👉 then이라는 함수를 통해서 chainig!!
  • resolve한 값을 뒤로 쭉쭉 넘겨줌 ❗

코드 설명2

new Promise((resolve, reject) => { 
  console.log('Inside promise')
  reject(new Error('Fist reject'))
  console.log('Before resolve')
  resolve('First resolve')
  console.log('After resolve')
})
  .then((value) => {
    console.log('Inside first then')
    console.log('value', value)
  })
  .catch((error) => {
    console.log('error', error) 
  })

❗ 실행 결과 ❗

  • 여기서 promise는 reject된 값으로 결정 ❗ ( resolve 값이 아닌 reject 값으로 넘겨주는 것)
  • 그래서, then은 실행X, catch로 넘어감
  • promise 값은 reject 값으로 결정됐지만 실행은 다 일어남! 실행 결과 보면 알 수 있음
  • catch에서 error 잡히고 error 출력
  • catch는 promise chain 상에서 가장 가까이 있는 error 잡아서 error 내줌

코드 설명3 (비동기)

// 비동기코드 setTimeout

new Promise((resolve, reject) => {
  console.log('Before timeout')
  setTimeout(() => {
    resolve(Math.random())
    console.log('After resolve')
  }, 1000) // 1초 뒤에 어떤 값 결정
})
  .then((value) => {
    console.log('then 1')
    console.log('value', value)
  })
  .then(() => {
    console.log('then 2')
  })
  .then(() => {
    console.log('then 3')
  })

// timeout 전에 콜솔로그 찍히고
// settimeout 실행 후 resolve실행
// 그 다음 then chain을 타고서 다음으로 넘어거ㅏㅁ
// promise는 비동기 코드를 순차적으로 쭉 이어지게 쓸 수 있게 만듦
// 비동기 코드가 위에서 아래로 순차적으로 쭉

❗ 실행 결과 ❗

  • timeout 전에 'Before timeout' console 찍히고
  • setTimeout 실행 후 resolve 실행
  • 그 다음 then chain 타고서 다음으로 넘어감
  • promise는 비동기 코드를 순차적으로 쭉 이어지게 쓸 수 있게 만듦

코드 설명4 (Promise Chain)

// 비동기코드 setTimeout

function returnPromiseForTimeout() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(Math.random())
    }, 1000) // 1초 뒤에 어떤 값 결정
  })
}
// 맨첨엔 setTimeout 갖고 resolve 1초 뒤에
// resolve 뒤에 then chain 탄다!
returnPromiseForTimeout()
  .then((value) => {
    console.log(value) // then chain에서 return한 값이 다시 promise를 리턴
    return returnPromiseForTimeout()
  }) // 그럼 다음 then chain에서는 promise가 리턴 됐기 때문에 promise가 resolve 될 때까지 기다린 다음에야 then 실행
  .then((value) => {
    console.log(value)
    return returnPromiseForTimeout
  })
  .then((value) => {
    console.log(value)
    return returnPromiseForTimeout
  })
  .then((value) => {
    console.log(value)
    return returnPromiseForTimeout
  })

returnPromiseForTimeout()

❗ 실행 결과 ❗

코드 설명5 (node에서 제공하는 promise 형태 api)

// @ts-check

const fs = require('fs')

/**
 * @param {string} fileName
 */
function readFileInPromise(fileName) {
  return new Promise((resolve, reject) => {
    fs.readFile(fileName, 'utf-8', (error, value) => {
      if (error) {
        reject(error)
      }
      resolve(value)
    })
  })
}
readFileInPromise('.gitignore').then((value) => console.log(value))

fs.promises.readFile('.gitignore', 'utf-8').then((value) => console.log(value))

둘 다 같은 일 일어남
매번 promise로 감싸주지 않아도 node에서는 promise 형태의 api 제공하고 있다.

promise와 async/await 관련성

/**
 * @param {number} duration
 */
async function sleep(duration) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(undefined)
    }, duration)
  })
}

async function main() {
  console.log('first')
  await sleep(1000)
  console.log('second')
  await sleep(1000)
  console.log('third')
  await sleep(1000)
  console.log('finish!')
  await sleep(1000)
}

main()
  • async function은 promise를 돌려주는 함수
  • promise를 return하는 함수는 async 함수로 만들 수 있다.
  • async function 안에서는 다른 async function await할 수 있다.

async/await에서 error 잡는 법❓ 👉 try/catch

// @ts-check

const fs = require('fs')

async function main() {
  try {
    const result = await fs.promises.readFile('.gitignore', 'utf-8')
    console.log(result)
  } catch (error) {
    console.log('error', error)
  }
}

main()

0개의 댓글