Help us understand the problem. What is going on with this article?

headタグ内におけるcharsetの挙動について

アプリケーション(サーバサイド)エンジニアから駆け出しフロントエンドエンジニアに転向したさむとるです。
今回はブラウザにおける文字コードの解釈・挙動における疑問を調べた結果をまとめました。

あらまし

WHATWGの規格書によると、
<script>タグはデフォルトの場合、htmlのパースを止めてjsのダウンロードと実行を行います。

そのため我々フロントエンジニアはしばしasyncdeferを用いたりすることで、速度向上を行おうとします

そこで私は疑問に思ってしまったのです

charset="utf-8"の前にutf-8で記述されている<script>を置いてしまった場合、文字化けするのではないか?と
※locale langageがja(日本語)の場合、デフォルトで文字コードはshift-jisになる->WHATWGの規格書

確認

確認するために下記のコードを適当に用意しました

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <script src="foo.js"></script> <!-- utf-8 -->
    <script src="bar.js"></script> <!-- shift-jis -->
    <meta charset="utf-8">
</head>
<body></body>
</html>
foo.js
alert('アラート1'); // utf-8
bar.js
alert('アラート2'); // shift-jis

結果

文字化けしませんでした

al1.PNG
al2.PNG

理由としては

The user agent may wait for more bytes of the resource to be available, either in this step or at any later step in this algorithm. For instance, a user agent might wait 500ms or 1024 bytes, whichever came first. In general preparsing the source to find the encoding improves performance, as it reduces the need to throw away the data structures used when parsing upon finding the encoding information. However, if the user agent delays too long to obtain data to determine the encoding, then the cost of the delay could outweigh any performance improvements from the preparse.

とあり、英語が読めないなりにざっくりと解釈したところ
1024byte分事前捜査し、そこに文字コードの指定があれば使用する
感じらしいです。勉強になりました。

追加検証

500ms/1024byteよりあとに<chaeset>をしたら文字化けするのでは?と思い追加検証を行いました。

chromeは頭が良すぎたのでIEで実行しました。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <script src="foo.js"></script> <!-- utf-8 -->
    <script src="bar.js"></script> <!-- shift-jis -->
    <script>// byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi</script>
    <script>// byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi</script>
    <script>// byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi byte kasegi</script>
    ...
    <meta charset="utf-8">
</head>
<body></body>
</html>

みたいな感じでbyte数稼ぎを行います

実行結果

al3.PNG al4.PNG
al5.PNG al6.PNG

<charset>が解釈されていないalartが実行された後に、再度文字コードが正しく解釈されたalartが表示され、計4回のアラートが表示されました
実行時のコンソールを確認したところ、2回目のalartの後に
console1.PNG
とあり、パーサーが文字コードを解釈した地点で先頭から再実行を行っていることが判明しました。

総括

<charset>の前にscriptを仕込むと2重で実行されてしまう可能性があり、
少なからずパフォーマンスに影響が出たり、計測系だったら2重送信されてめんどくさい場合が無きにしも非ずなので
基本何があっても初手<charset>したほうがいいかもしれません

sumtrue
lifull
日本最大級の不動産・住宅情報サイト「LIFULL HOME'S」を始め、人々の生活に寄り添う様々な情報サービス事業を展開しています。
https://lifull.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away