15. 이벤트 처리 (15.6 ~ 8)

Veloger_97·2021년 8월 6일
0
post-thumbnail

15.6 이벤트 리스너에 추가적인 정보를 넘기는 방법👊


15.6.1 익명 함수 안에서 실행하기

익명 함수를 이벤트 리스너로 지정하고 이벤트 리스너 안에서 함수를 실행하면 그 함수에 추가적인 정보를 값으로 넘길 수 있다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="box">click me</div>
    <script>
      window.onload = function () {
        var box = document.getElementById("box");
        box.addEventListener("click", changeBgColor("red"), false);
        function changeBgColor(color) {
          return function (e) {
            e.currentTarget.style.backgroundColor = color;
          };
        }
      };
    </script>
  </body>
</html>

15.7 커스텀 이벤트👊

객체와 객체 사이의 관계를 느슨하게 연결하는 수단

15.7.1 커스텀 이벤트를 생성하는 방법

click이나 mousedown등의 표준 이벤트 외에 독자적인 이벤트를 생성할 수 있다.
createEvent 메서드로 이벤트 객체를 생성 -> dispatchEvent 메서드를 호출해서 이벤트를 보냄


15.7.2 이벤트 객체 생성

코드에서 type은 생성할 이벤트 객에의 이벤트 타입을 뜻한다.

var event = document.createEvent(type);

생성된 이벤트 객체는 해당 이벤트의 타입에 따라 초기화 작업을 해야 한다.

event.initEvent(type, bubbles, cancelable);

// type : 이벤트 유형을 뜻하는 문자열("click", "mouseup" 등)
// bubbles : 버블링할지를 나타내는 논리값
// 버블링 설명 : https://ko.javascript.info/bubbling-and-capturing
// cancelable : 취소할 수 있는 이벤트로 만들지를 나타내는 논리값

15.7.3 이벤트 보내기

초기화 작업을 끝낸 후에는 이벤트 타깃 요소를 상대로 이벤트를 보낸다. 이벤트는 요소 객체의 dispatchEvent 메서드로 보낸다.

target.dispatchEvent(event);

앞서 정의한 이벤트 객체를 사용해서 button 객체에 이벤트를 보내려면 다음과 같이 작성한다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <p>
      <button id="button">버튼</button>
    </p>
    <script>
      window.onload = function () {
        var event = document.createEvent("HTMLEvents");
        event.initEvent("click", true, false);
        var button = document.getElementById("button");
        button.addEventListener("click", function (event) {
          alert(`event.cancelable : ${event.cancelable}`);
        });
        button.dispatchEvent(event);
      };
    </script>
  </body>
</html>

15.7.4 커스텀 이벤트와 표준 이벤트의 차이점

커스텀 이벤트는 이벤트 객체의 isTrusted 프로퍼티로 구별 가능하다. isTrusted 값이 true면 표준이벤트, false면 커스텀 이벤트

15.7.5 커스텀 이벤트의 용도

커스텀 이벤트의 사용 이유

객체와 객체가 통신하는 주요 수단은 인수로 콜백함수를 넘기는 것이며 또 다른 방법은 커스텀 이벤트를 보내는 것이다. 즉, 한쪽 객체에서는 이벤트 발생, 다른 한쪽 객체에서는 이벤트를 처리하는 리스너를 등록해서 처리한다.

15.8 비동기 처리를 간결하게 작성하는 Promise👊


15.8.1 비동기 처리의 예

console.log("A");
setTimeout(function () {
  console.log("B");
}, 0);
console.log("C");

위 코드의 실행 결과는 A -> C -> B 순서로 콘솔에 표시된다. setTimeout함수의 인수로 받은 콜백 함수는 시간이 흐른 후에 처리하도록 예약처리만하고 다음 코드로 넘어가기 때문이다.


다음 코드는 1초 후에 "A" 1초 후에 "B" 1초 후에 "C"를 표시하는 코드이다. sleep 함수는 callback이라는 콜백 함수를 1초 후에 실행하는 방식으로 비동기 처리를 구현했다.

function sleep(callback) {
  setTimeout(function () {
    callback();
  }, 1000);
}

sleep(function () {
  console.log("A");
  sleep(function () {
    console.log("B");
    sleep(function () {
      console.log("C");
    });
  });
});
// A, B, C

위 코드처럼 콜백함수를 여러 개 중첩하면 이해하기 어려워지는데 이를 콜백지옥이라고 부른다. Promise를 사용해서 이와 같은 문제를 해결할 수 있다.


15.8.2 Promise의 기본

Promise는 비동기 처리를 하고 다음 처리를 실행하기 위한 용도로 사용된다. Promise를 사용하려면 객체를 생성해야 한다.

var promise = new Promise(funtion(resolve, reject) {...});

// resolve : 함수 안의 처리가 끝났을 때 호출해야 하는 콜백 함수.

// reject : 함수 안의 처리가 실패했을 때 호출해야 하는 콜백 함수
var promise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    console.log("A");
    resolve();
  }, 1000);)
});
promise.then(function() {
  console.log("B");
})

// A, B

위의 코드에서 Promise에 인수로 넘긴 함수는 비동기 처리를 수행하는 함수이다. 1초 후에 "A"를 표시하고, resolve함수를 호출해서 Promise 안의 처리를 종료한다.
resolve 함수가 실행되면 then 메서드에 등록한 함수가 호출된다.


15.8.3 Promise를 종료시키는 resolve 함수와 then 메서드

resolve 함수에 인수로 넘긴 값은 then 메서드에 인수로 넘긴 함수에 전달되어 다음 처리를 위해 사용한다.

promise.then(onFullfilled);

위 코드에서 onFullfilled 함수는 성공 콜백 함수라고 하며 promise 안의 처리가 정상적으로 끝났을때 호출된다.

var promise = new Promise(function (resolve, reject) {
  setTimeout(function () {
    var name = prompt("이름을 입력하세요.");
    resolve(name);
  }, 1000);
});
promise.then(function (name) {
  console.log(`안녕하세요 ${name}`);
});

15.8.4 Promise를 실패로 처리하는 reject 함수와 catch 메서드

resolve와 마찬가지로 reject 함수에도 값을 넘길 수 있다. then 대신 catch 메서드에 넘긴 함수가 실행된다.

promise.catch(onRejected);

위 코드에서 onRejected 함수는 실패 콜백 함수라고 하며 promise 안의 처리가 실패로 끝났을때 호출된다.

15.8.5 then의 두번쨰 인수

promise.then(onFullfilled, onRejected);

promise 안의 처리가 성공하면 onFullfilled 함수가 실행되고 실패하면 onRejected 함수가 실행된다.

15.8.6 Promise가 실행하는 콜백 함수에 인수 넘기기

function buyAsync(money) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      var payment = parseInt(prompt("지불하고자 하는 금액을 입력하세요"));
      var balance = money - payment;
      if (balance > 0) {
        console.log(`${payment}원을 지불했습니다.`);
        resolve(balance);
      } else {
        reject(`구매할 수 없습니다. 잔액은 ${money}원 입니다.`);
      }
    }, 1000);
  });
}

buyAsync(500)
  .then(function (balance) {
    console.log(`잔액은 ${balance}원 입니다.`);
  })
  .catch(function (error) {
    console.log(error);
  });

15.8.7 Promise로 비동기 처리 연결하기

function buyAsync(money) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      var payment = parseInt(prompt("지불하고자 하는 금액을 입력하세요"));
      var balance = money - payment;
      if (balance >= 0) {
        console.log(`${payment}원을 지불했습니다.`);
        resolve(balance);
      } else {
        reject(`구매할 수 없습니다. 잔액은 ${money}원 입니다.`);
      }
    }, 1000);
  });
}

buyAsync(500)
  .then(function (balance) {
    console.log(`잔액은 ${balance}원 입니다.`);
    return buyAsync(balance);
  })
  .then(function (balance) {
    console.log(`잔액은 ${balance}원 입니다.`);
    return buyAsync(balance);
  })
  .then(function (balance) {
    console.log(`잔액은 ${balance}원 입니다.`);
    return buyAsync(balance);
  })
  .catch(function (error) {
    console.log(error);
  });

15.8.8 비동기 처리 여러 개를 병렬로 실행하기

Promise.all 메서드
Promise의 all 메서드는 모든 처리가 성공적으로 끝났을 때만 다음 작업을 실행하도록 한다.

Promise.all(iterable);

iterable은 반복 가능한 객체이다.

예를 들어 Promise 객체가 요소로 들어있는 배열을 넘기면 Promise.all 메서드는 그 안의 요소로 들어있는 모든 Promise 객체를 병렬로 실행한다.

resolve 호출 -> then 메서드 실행 (인수로 response라는 배열을 받음)

실패로 끝난 Promise 객체가 하나라도 있다면 가장 먼저 실패로 끝난 Promise 객체에서 실행한 reject 함수의 인수를 실패 콜백 함수에 인수로 넘긴다.

function buyAsync(name, money) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      var payment = parseInt(
        prompt(`${name}님, 지불하고자 하는 금액을 입력하세요.`)
      );
      var balance = money - payment;
      if (balance > 0) {
        console.log(`${name} : ${payment}원을 지불했습니다.`);
        resolve(balance);
      } else {
        reject(`${name} : 잔액은 ${balance}원 입니다. 구매 불가능`);
      }
    }, 1000);
  });
}

Promise.all([
  buyAsync("Tom", 500),
  buyAsync("Huck", 600),
  buyAsync("Becky", 1000),
])
  .then(function (balance) {
    console.log(balance);
  })
  .catch(function (error) {
    console.log(error);
  });

Promise.race 메서드
Promise의 race 메서드는 가장 먼저 종료한 Promise 객체의 결과만 다음 작업으로 보낸다.

function buyAsync(name, money) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      var payment = parseInt(
        prompt(`${name}님, 지불하고자 하는 금액을 입력하세요.`)
      );
      var balance = money - payment;
      if (balance > 0) {
        console.log(`${name} : ${payment}원을 지불했습니다.`);
        resolve(balance);
      } else {
        reject(`${name} : 잔액은 ${balance}원 입니다. 구매 불가능`);
      }
    }, 1000);
  });
}

Promise.race([
  buyAsync("Tom", 500),
  buyAsync("Huck", 600),
  buyAsync("Becky", 1000),
])
  .then(function (balance) {
    console.log(balance);
  })
  .catch(function (error) {
    console.log(error);
  });
profile
프론트엔드 개발자가 되고 싶어요 🙆‍♂️

0개의 댓글

관련 채용 정보