defer vs DOMContentLoaded

  • defer이 먼저 실행된다

defer 여러개 실행 순서

1
2
<script src="./defer.js" defer></script>
<script src="./defer2.js" defer></script>
  • 여러개의 defer가 있으면 위에서 아래로 순서대로 실행된다
  • defer.js 실행 -> defer2.js 실행

async와 DOMContentLoaded는 서로 무관하다

  • DOMContentLoaded 먼저 실행될수도 async가 먼저 실행될수도 있다

참고

script태그 defer, async

  • 처음 웹 프로그래밍을 배울 때 스크립트 태그는 body 최하단에 위치시키라고 배웠다
  • 스크립트 로드 타이밍을 뒤로 미뤄서 돔을 조작하는 스크립트가 잘 동작한다
  • 근데 요즘에는 스크립트 태그를 head 안에 선언하는 경우가 많다
  • defer를 사용하면 위에서 말한 효과를 볼 수 있다
  • 근데 defer 말고도 async라는 속성을 줄 수 있다
  • 둘이 차이는 뭘까?

default (blocking further parsing)

  • 스크립트 태그를 만나면 파싱을 멈추고 스크립트를 로드하고 실행한다
  • 이 때 HTML 파싱을 멈춘다
  • 스크립트가 로드 다 끝나면 이어서 남은 파싱을 진행한다
  • 스크립트가 헤비 하면 화면이 안 그려지고 사용자가 떠날 확률도 높아지겠다

defer, async 공통

  • 스크립트는 스크립트대로 로드하고 HTML 파싱은 계속된다
  • 비동기적이다

defer

  • 스크립트 로드가 완료되었다고 바로 실행되지 않는다
  • HTML 파싱이 모두 끝나면 실행된다
  • 주로 돔을 조작하는 스크립트를 로드할 때 사용하면 된다

async

  • 스크립트가 로드되고 바로 실행된다
  • 돔을 조작하는 스크립트가 없을 때 사용하는 것이 좋다

참고

blog fix 카피 버튼이 안나오는 문제

  • 블로그에 코드 스니펫 오른쪽 위에 카피 버튼이 나올 때도 있고 안 나올 때도 있었다
  • 무한 새로고침하면 종종 모습을 비춘다… (이스터에그도 아닌 것이..)

환경

  • hexo-theme-icarus v4.0.1

해결하기

  • 일단 어디서 이 버튼을 생성하는지 알아내야 한다
  • 버튼이 정상적으로 출력되었을 때 해당 버튼의 클래스명을 확인했다
  • 그리고 main.js라는 곳에서 동적으로 버튼을 생성하고 있음을 알아냈다
themes\icarus\source\js\main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
console.log(clipboard, typeof ClipboardJS);
if (typeof ClipboardJS !== 'undefined' && clipboard) {
$('figure.highlight').each(function () {
const id = 'code-' + Date.now() + ((Math.random() * 1000) | 0);
const button =
'<a href="javascript:;" class="copy" title="Copy" data-clipboard-target="#' +
id +
' .code"><i class="fas fa-copy"></i></a>';
$(this).attr('id', id);
$(this).find('figcaption div.level-right').append(button);
});
new ClipboardJS('.highlight .copy'); // eslint-disable-line no-new
}
  • 조건문에 ClipboardJS가 있으면 버튼을 생성하는데
  • main.js에는 ClipboardJS에 대해 따로 선언이 없었고, 외부 라이브러리라는 것을 알았다
  • 이 ClipboardJS가 어디서 오는지 확인해야 했다
themes\icarus\layout\common\scripts.jsx
1
2
3
4
5
6
7
8
9
{
clipboard && (
<script
src={cdn('clipboard', '2.0.4', 'dist/clipboard.min.js')}
// async
defer
></script>
);
}
  • layout\common\scripts.jsx에서 가져오는 코드를 확인했는데
  • async으로 가져오고 있었다
  • 문제는 clipboardJS가 로드되기 전에 main.js가 먼저 실행되는 문제였다
  • defer로 수정하니까 잘 동작했다!

최신 버전 확인

  • hexo-theme-icarus v4.2.0
  • 최신 버전을 확인하니까 defer로 변경되어있었다… (이슈 검색했을 때는 못 찼았다…)
  • 처음부터 최신 버전을 참고하면 좋았겠다
  • 9개월 정도 나름대로 커스텀하면서 사용해왔는데,
  • 나중에 시간 나면 커스텀한 내용을 유지하면서 최신 버전에 맞게 업데이트해줘야겠다

참고

async, defer