SeonHyungJo / Tip-Note

:round_pushpin: 개발을 하면서 느끼고 알게된 Tip:round_pushpin:
7 stars 0 forks source link

여러 팝업을 순서에 맞게 비동기로 띄우기 #76

Open SeonHyungJo opened 3 years ago

SeonHyungJo commented 3 years ago

개발을 하다보면 다양한 퍼널을 개발하게 된다.

퍼널이라 함은 페이지 단위로 기획이 될 수 있지만, 순서가 있는 팝업이 될 수 있다.

예를 들어보자. 사용자가 이메일을 입력하는 팝업과 설문조사 팝업을 연달아 띄운다고 생각하자. 그렇다면 이메일을 입력하고 확인버튼을 누르는 순간 우리는 API를 호출하여 업데이트하고 다음 팝업을 띄울 것이다.

그런데 요구조건이 새로 생겨서 이메일이 있으면 설문조사만 띄우고 설문조사가 되어있으면 이메일만 띄우게 되었다. 쉽게 생각하면 4가지의 경우의 수가 생겼고, 당연히 if문으로 처리해야한다고 생각하게 된다.

if(이메일이 없으면){
  // 이메일 팝업 띄우기
  if(설문조사 안한 경우){
    //설문조사 팝업 띄우기
  }
} else if(설문조사 안한 경우){
  //설문조사 팝업 띄우기
}

이 정도의 코드가 나올 것이다. 생각보다 별거없다고 생각할 수 있지만, 팝업이 4개라면?(2^4) 팝업이 8개라면?(2^8)개의 경우의 수가 나올 것이다. 더욱이 순서를 지켜줄려고 한다면 우리는 이제 포기할지 모른다.

이를 좀 더 쉽게 생각해보자.

if(이메일이 없으면){
  // 이메일 팝업 띄우기
}

if(설문조사 안한 경우){
  //설문조사 팝업 띄우기
}

이렇게 하면 되지 않나? 그런데 이는 이메일 팝업이 닫히고 설문조사 팝업이 띄워진다는 보장을 못하고, 이메일 팝업이 띄워져 있는 상태에서 설문조사 팝업을 또 띄울 수 있는 것이다.

이를 비동기로 만들면서 순서도 보장해주면서 경우의 수를 생각하지 말고 개발해보자.

PopupContainer.js

export default function (e) {
  console.log('popup', e.descVue())

  setTimeout(() => {
    e.yesFunc()
  }, 2000);
}

먼저 우리가 사용하는 Page관련 컴포넌트를 팝업으로 만들어주는 Container를 만들어 준다.

Popup.js

import PopupContainer from './PopupContainer.js'

export const Popup = {
  openRentalEmail: function () {
    return new Promise((resolve, reject) => {
      import('./RentalEmail.js').then(RentalEmailPopup => {
        PopupContainer({
          descVue: RentalEmailPopup.default,
          yesFunc: () => {
            resolve()
          }
        })
      }).catch(reject)
    })
  },

  openUseCountPopup: function () {
    return new Promise((resolve, reject) => {
      import('./RentalUseCount.js').then(RentalUseCountPopup => {
        PopupContainer({
          descVue: RentalUseCountPopup.default,
          yesFunc: () => {
            resolve()
          }
        })
      }).catch(reject)
    })
  }
}

우리가 많이 사용하는 팝업을 모듈로 만들어서 정의를 한다.

RentalEmail.js

export default function () {
  return 'RentalEmail'
}

RentalUseCount.js

export default function () {
  return 'RentalUseCount'
}

팝업 컨테이너 안에 들어갈 내용의 모듈들도 만들어 준다.

Popup.js에 모듈들은 비동기적으로 호출하여 팝업을 호출할 때만 리소스를 불러오도록 처리하였다. 이제 마지막으로 팝업이 띄워질 순서에 맞춰 정의를 하고 이메일이 있거나, 설문조사를 이미 참여한 경우 건너뛰는 로직을 만들어 주면 된다.

index.html

<script type='module'>
  import {Popup} from './Popup.js'

  function openEmailPopup() {
    if (myEmail === '') {
      return new Promise((resolve, reject) => {
        Popup.openRentalEmail().then(resolve).catch(reject)
      })
    }
  }

  function openUseCountPopup() {
    if (mySurveyResult === '') {
      return new Promise((resolve, reject) => {
        Popup.openUseCountPopup().then(resolve).catch(reject)
      })
    }
  }

  const popupFunnel = [openEmailPopup, openUseCountPopup]
  const myEmail = '' // DB Data
  const mySurveyResult = '' // DB Data

  async function executePopupFunnel() {
    for (let i = 0; i < popupFunnel.length; i++) {
      await popupFunnel[i]()
    }
  }

  executePopupFunnel()
  Popup = null
</script>

팝업이 띄워질 순서대로 리스트에 담았다. 그리고 각각의 함수 안에서 이미 값이 있는 판단하여 없다면 팝업을 띄우도록 호출하고 아니라면 다음 순서의 팝업 함수를 실행시키고 있다.

중요한 부분은

async function executePopupFunnel() {
    for (let i = 0; i < popupFunnel.length; i++) {
      await popupFunnel[i]()
    }
  }

이 부분으로 리스트 안에 담겨진 Promise를 리턴하는 함수들을 await로 대기하면서 확인 버튼을 누를 때까지 기다리게 된다.