Javascript 비동기 고급

jimin·2022년 7월 25일
0

nodeJs

목록 보기
4/5

비동기적으로 초기화되는 컴포넌트 다루기

동기 api가 구현은 편하지만 항상 그럴수는 없다. 그렇기에 비동기적으로 초기화 작업을 구현하는 방법을 알아보자.

아래는 비동기적으로 초기화된 컴포넌트의 일반적인 예이다.

예시 (db.js)

import { EventEmitter } from 'events'

class DB extends EventEmitter {
  connected = false

  connect () {
    // 연결 지연 시뮬레이션
    setTimeout(() => {
      this.connected = true
      this.emit('connected') 
    }, 500)
  }

  async query (queryString) {
    if (!this.connected) {
      throw new Error('Not connected yet')
    }
    console.log(`Query executed: ${queryString}`)
  }
}

export const db = new DB()

위의 db모듈은 초기화가 완료될때까지 다른 작업을 할 수 없다.
이 문제에 대한 두가지 해결책
1) 로컬 초기화
2) 지연 시작

로컬 초기화

API가 호출되기 전에 모듈이 초기화 되었는지 확인 그렇지 않으면 초기화되기를 기다린다.

import { once } from 'events'
import { db } from './db.js'

db.connect()

async function updateLastAccess () {
  if (!db.connected) {
    await once(db, 'connected') // 해당 이벤트 발생 시까지 실행 중단.
  }

  await db.query(`INSERT (${Date.now()}) INTO "LastAccesses"`)
}

updateLastAccess()
setTimeout(() => {
  updateLastAccess()
}, 600)

지연 시작

컴포넌트가 초기화 루틴을 완료할 때까지 비동기적으로 초기화된 컴포넌트에 의존하는 코드의 실행을 지연시키는 것

import { once } from 'events'
import { db } from './db.js'

async function initialize () {
  db.connect()
  await once(db, 'connected')
}

async function updateLastAccess () {
  await db.query(`INSERT (${Date.now()}) INTO "LastAccesses"`)
}

initialize()
  .then(() => {
    updateLastAccess()
    setTimeout(() => {
      updateLastAccess()
    }, 600)
  })

단점 : 비동기적으로 초기화되어야 하는 컴포넌트를 사용하는 컴포넌트가 어떤 것인지 미리 알아야한다.

비동기 초기화 단계가 완료될 때까지 모든 작업을 투명하고 효율적으로 지연시킬수있는 사전 초기화 큐

사전 초기화 큐

컴포넌트가 아직 초기화되지 않은 상태에서 수신된 함수 호출을 큐에 넣은 다음, 모든 초기화 단계가 완료되는 즉시 실행하는 것이다.

import { EventEmitter } from 'events'

class DB extends EventEmitter {
  connected = false
  commandsQueue = []

  async query (queryString) {
    if (!this.connected) {
      console.log(`Request queued: ${queryString}`)
      
      return new Promise((resolve, reject) => {
        const command = () => {
          this.query(queryString)
            .then(resolve, reject)
        }
        this.commandsQueue.push(command)
      })
    }
    console.log(`Query executed: ${queryString}`)
  }

  connect () {
    setTimeout(() => {
      this.connected = true
      this.emit('connected')
      this.commandsQueue.forEach(command => command())
      this.commandsQueue = []
    }, 500)
  }
}
export const db = new DB()

비동기식 요청 일괄 처리 및 캐싱

비동기식 요청 일괄 처리

비동기 작업을 처리할때 동일한 API에 대한 일련의 호출을 일괄처리하여 가장 기본적인 수준의 캐싱을 수행할수 있다.

최적의 비동기 요청 캐싱

요청이 완료되자마자 그 결과를 캐시에 저장한다. 따라서 다음에 API가 호출될때 다른 요청을 생성하는 대신 캐시에서 즉시 결과를 검색할 수 있다.

참고
Node.js 디자인 패턴 바이블 - 영진닷컴

profile
안녕하세요 백엔드 개발자 지민입니다.

0개의 댓글