[번역] You’ve Got Options for Removing Event Listeners

정호진·2023년 2월 5일

번역

목록 보기
1/2

영어 공부를 해야겠다는 생각에 시작하게 되었습니다. 매 주마다 자바스크립트 관련된 자료들을 메일로 받는데, 해당 자료 중 제목을 보고 흥미가 가는 것을 번역해 봤습니다. 나름 열심히 했지만 의역하는데 있어서 상당히 발번역이라 이 점 감안하고 봐주시면 정말 감사하겠습니다.

번역을 하면서 파파고와 함께 한줄 번역하고 한줄 확인하고를 반복했습니다. 정말 제가 모르는 어휘와 구문이 많았고 내가 이정도로 못했나? 라는 생각이 들 정도였습니다. 꾸준하게 하면 분명히 뭐라도 있겠지 라는 생각에 주에 하나씩 스크랩을 올려볼까 합니다.

오역이 있다면 바로 지적해주세요!


원문: https://www.macarthur.me/posts/options-for-removing-event-listeners


이벤트 리스를 사용하지 않아도 된다.

자바스크립트에서 이벤트 리스너를 사용하지 않는 몇몇 일반적인 방법에 대해서…

런타임 환경에서 코드를 정리하는 것은 효율적이고 예측할 수 있는 어플리케이션을 구축하는 과정에서 양보할 수 없는 부분입니다. 자바스크립트에서 위의 방법을 실행할 방법의 하나는 이벤트 리스너를 잘 관리(by stewarding)하는 것이다. — 특히 더 이상 필요하지 않은 이벤트 리스너들을 제거하는 데 있어서.

위 방법을 할 수 있는 몇 가지 방법들이 존재하는데, 각각의 방법들은 그것들을 특정 상황에서 좀 더 적합하게 만드는 절충안을 가지고 있습니다. 우리는 자주 사용되는 몇몇 방법과 주어진 시간 내에 서 어떤 것이 가장 적합한지 결정할 때 고려해야 할 몇몇 사항들에 관해 이야기하고자 합니다.

우리는 button에 단일 클릭 이벤트 리스너가 부착된 예를 수정해 볼 것입니다.

<button id="button">Do Something</button>

<script>
document.getElementById('button').addEventListener('click', () => {
	console.log('clicked!');
});
</script>

크롬의 getEventListeners() 기능을 사용한다면 엘레멘트에 부착된 이벤트 리스너들을 볼 수 있습니다. (추가로, f12 → Element tab → styles 등 구조를 나타내는 정보 칸에 >> 버튼을 누른다면 Event Listeners 탭이 나타납니다)

위에 해당하는 이벤트는 제거해야 할 이벤트입니다. 이벤트 제거를 시도할 방법은 아래와 같습니다.

.removeEventListener() 사용

해당 메서드는 아마 가장 명백한 방법이지만, 가장 위험한 방법이기도 합니다. removeEventListener() 메서드는 제거 타입, 해당 리스너에 대한 콜백 함수 그리고 옵션 객체라는 3개의 파라미터를 받습니다.

하지만 여기에 잠재적으로 까다로운 부분이 있습니다. 바로 이 정확한 파라미터들은 콜백 메모리에대한 동일한 참조를 포함해서 처음 설정할 때 사용된 것들 반드시 일치해야 합니다. 만약 그렇지 않다면 removeEventListener() 메서드 아무것도 하지 않습니다.

이 점을 생각한다면, 아래 예시는 비효율적일 것입니다.

document.getElementById('button').addEventListener('click', () => {
	console.log('clicked!');
});

document.getElementById('button').removeEventListener('click', () => {
	console.log('clicked!');
});

비록 콜백 함수가 원본과 동일하게 장착되었지만, 이것은 같은 레퍼런스가 아닙니다. 이것의 해결 방법은 해당 콜백 함수를 변수로 설정하고, .addEventListener()와 .removeEventListener()에 참조하도록 설정하는 것입니다.

const myCallback = () => {
  console.log('clicked!');
};

document.getElementById('button').addEventListener('click', myCallback);
document.getElementById('button').removeEventListener('click', myCallback);

또는 콜백 함수 선언을 일반형으로 선언한 뒤 함수 내에서 this를 사용해서 스스로 .removeEventListener() 메서드를 통해 제거하는 특별 케이스도 있습니다.

document
  .getElementById('button')
  .addEventListener('click', function myCallback() {
    console.log('clicked!');

    this.removeEventListener('click', myCallback);
  });

이러한 독특한 사용 방법에도 불구하고 .removeEventListener()는 사용 목적이 명확하다는 장점이 있고, 이는 해당 코드의 역할을 손쉽게 알 수 있습니다.

**Using .addEventListener()’s once Option

.addEventListener() 메서드는일회용으로 사용할 수 있는 도구를 가지고 있습니다. - once 옵션입니다. 이것은 듣는 것만으로도 간단함을 알 수 있습니다. 만약 이 옵션을 true로 설정한다면, 리스너는 첫 번째 실행(호출) 이후에 자동으로 해당 리스너를 삭제합니다.

const button = document.getElementById('button');

button.addEventListener('click', () => {
	console.log('clicked!');
}, { once: true });

// 'clicked!'
button.click();

// No more listeners!
getEventListeners(button) // {}

당신의 사용 예시에 알맞다면, 만약 당신이 익명함수를 간절히 원하고, 단 한 번만 호출되기를 원하는 경우에 이 접근 방법은 적절할 것입니다.

리스너를 한 번만 호출하면 된다는 점에서 익명 함수를 사용하는 경우에 이 방법이 적합할 수 있습니다.

노드의 복사 및 대체

때때로 주어진 노드들에서 활성화된 모든 리스너들에 대해 모르지만, 그들을 핵으로 만들고 싶어 한다는 것은 알고 있습니다. 이러한 경우에, 이것은 노드 전체를 복제하고 해당 클론으로 대체할 수 있습니다. .cloneNode() 메서드를 사용한다면 비단 .addEventListener()를 통해 장착된 리스너들 중 어느 리스너도 전달되지 않고 깨끗한 상태로 주어질 것입니다.

과거의 client-side Javascript로 돌아간다면, 부모로부터 조회하며 특정 자식 노드들이 복제된 것들로 대체되어 완료되는 것을 볼 수 있습니다.

button.parentNode.replaceChild(button.cloneNode(true), button);

그러나 현재 브라우저에서는 이 작업은 .replaceWith() 로 간단하게 대체되었습니다.

button.replaceWith(button.cloneNode(true));

당신이 실수할 수 있는 유일한 것은 본질적인 리스너들은 보존된다는 것입니다. 이 의미는 버튼에 있는 onclick특성은 여전히 정의되어 있다는 것입니다.

<button id="button" onclick="console.log('clicked!')">
	Do Something
</button>

전반적으로, 만약 무차별적으로 어느 종류의 리스너들을 삭제하기를 원한다면 달성할 가치가 있는 옵션입니다. 그러나 부정적인 측면에서 이것은 목적이 명확하지 않기 때문에 어려움(고통)을 받고 있습니다. 몇몇은 이것을 해킹이라고 부르기도 합니다.

**AbortController() 사용하기

처음 보는 기술입니다. 나는 Caleb Porizo의 이 트윗을 우연히 발견했을 떄 말 그대로 이것을 읽기만 했습니다. 만약 당신이 나와 같다면, AbortControllerfetch() 요청을 취소하는 것에 대해 들어보기만 했을 것입니다. 하지만 이것은 그것보다 더 유연합니다.

최근 들어서 .addEventListener()는 명령적으로 리스너를 중단하거나/삭제하는 signal과 함께 형상화될 수 있습니다. 각각의 컨트롤러는 .abort()를 호출할 때 그 signal은 리스너를 제거할 수 있는 방아쇠가 됩니다.

const button = document.getElementById('button');
const controller = new AbortController();
const { signal } = controller;

button.addEventListener('click', () => console.log('clicked!'), { signal });

// Remove the listener!
controller.abort();

이것의 가장 뚜렷한 장점은 인간공학적이라는 것입니다. (내 생각에) 이것은 잠재적으로 .removeEventListener()를 다루지 않고 매우 깔끔하게 리스너를 제거할 방법입니다. 하지만 여기에는 좀 더 전략적인 이점이 더 있습니다. 바로 어느 정렬도 사용하지 않고 한 번에 단 한 개의 signal로 여러 개의 리스너들을 제거할 수 있다는 것입니다.

const button = document.getElementById('button');
const controller = new AbortController();
const { signal } = controller;

button.addEventListener('click', () => console.log('clicked!'), { signal });
window.addEventListener('resize', () => console.log('resized!'), { signal });
document.addEventListener('keyup', () => console.log('pressed!'), { signal });

// Remove all listeners at once:
controller.abort();

단 한 가지 단점은 브라우저 호환성입니다. 이것은 비교적 신기술이고 오직 2021년 이후의 크롬 버전(v90)만 지원합니다. 따라서 몇 년 이상 된 브라우저를 지원하는 경우 이것을 명심해야 합니다.

무엇을 사용해야 할까?

다른 모든 것들과 마찬가지로 “상황에 따라 다릅니다.” 여기에 차례대로 어떤 상황에 어떻게 선택해야 하는지 알려드리겠습니다.

  • .removeEventListener() : 콜백 함수가 변수로 선언되어 있고 리스너들이 쉽게 추가될 수 있는 경우
  • once option : 단 한 번만 콜백을 사용하는 경우
  • clone & replacement : 무차별적으로 다량의 듣는 이들을 단번에 처리하는 경우
  • AbortController() : 여러개의 듣는 이들을 가지고 있고 명령적으로 한번에 삭제를 원하는 경우 또는 단지 구문을 좋아하는 경우

놓친 것들

이것들 외에 다른 옵션들을 놓쳤을 가능성은 농후합니다. 만약 우연히 다른 방법을 알게 된다면 자유롭게 댓글을 달거나 또는 다른 방법을 알려주십시오. 적어도 저는 listeners를 깔끔하게 정리할 수 있는 몇 가지 방식들이 도움이 되길 바라며 또한 코드에서 리스너들을 관리할 때를 대비해서 도움이 되길 바랍니다.


어휘

by stewarding: by ~ ing (~~ 함으로써), 관리(steward)함으로써
each with its own set of trade-offs: 각각의 절충안을 갖고 있다.
here’s what you might reach for : 다음과 같은 방법을 선택할 수 있다.
But herein lies the (potentially) tricky part: 잠재적으로 까다로운 부분이 있다.
by querying up: 조회하며
The one thing that could potentially trip you up here: 당신이 유일하게 걸려 넘어질 수 있는 것
In all : 전반적으로
On the downside, however,: 그러나 부정적인 측면에서
go so far as to do something :~하기도 한다?
came across: 우연히 발견하다.
being used to: ~하곤 했다.
be configured: 형상화되다, 구성되다
it depends: 상황에 따라 다르다.
one over the other: 차례차례로
indiscriminately : 무차별적으
in one fell swoop: 단 한번
in addition to these: 이것들 외에
happen to have one: 우연히 갖게 되다
At the very least: 최소한(적어도)

0개의 댓글