【JavaScript】ChatGPTも知らない window.location の秘密

こんにちは。[ぬこすけ](https://twitter.com/nuko_suke_dev)です。

入社したてのフロントエンドエンジニアであれ、開発歴十年ベテランの Web 開発者であれ、 JavaScript で `window.location` を使って URL を変更するようなコードを見たことあるのではないでしょうか。

```javascript
window.location = "https://qiita.com/nuko-suke/items/a5bf4df00932b66847fc";
```

普段なにげなく使っているコードでも、実は面白い裏の仕組みがあったりします。
最たる例は `setTimeout` です。

https://qiita.com/nuko-suke/items/5b16ab9de402547c5797

実は `window.location` も深掘っていくと興味深い事実を見つけることができます。
今話題の ChatGPT に聞いてみます。

![ChatGPTとのやりとり](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164159/4cba8a90-69df-59ce-eadd-b0684746124c.png)

うーん、期待する回答ではなかったです。

今回は **`window.location` で URL を変更した時に裏でどのような仕組みでブラウザが動くのか** を深掘っていきたいと思います！
本来は難しい内容ですが、 **初心者の方でもわかりやすく説明** したいと思います。

:::note warn
- これからお話する内容は Google Chrome ブラウザでのお話です。
- URL の変更は「別サイトへの遷移」という前提でお話します。
:::

## Google Chrome ブラウザの仕組み

`window.location` の秘密をお話する前に、 Google Chrome がどのように動いているかを知っておく必要があります。

Chrome は **マルチプロセスアーキテクチャ** を採用しています。
普段何気なく Chrome を使って Web サイトを閲覧していますが、裏では複数のプロセスが立ち上がってブラウザが動いています。

Chrome では色々なプロセスが動いていますが、中でも **ブラウザプロセス** と **レンダラープロセス** は `window.location` の秘密を語るうえで重要です。

![Different processes pointing to different parts of browser UI](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164159/7c302758-1d04-8530-643d-956f04c04f14.png)
([Inside look at modern web browser (part 1)](https://developer.chrome.com/blog/inside-browser-part1/)より引用)

**ブラウザプロセス** はブラウザのアドレスバーや戻る/進むボタンなどの UI 部分に制御していることに加えて、外部へリクエストやファイルアクセスなども担当します。

ブラウザのタブを開くと Web ページが表示されますが、このタブ内のページ表示を担当するのが **レンダラープロセス** です。
HTML や CSS を解析したり、 JavaScript を実行したりといった作業はレンダラープロセスで行われます。
そしてもう 1 つタブを開くとまた別のレンダラープロセスが立ち上がるわけです。

このブラウザプロセスとレンダラープロセスは完全に独立して仕事をしているわけではなく、 **互いにコミュニケーションをとりながら 協力して Web ページを表示** します。
例えば「ブラウザのアドレスバーに URL を入力する」ケースを考えてみましょう。

## ブラウザのアドレスバーに URL を入力するとどうなる？

ザックリ次のステップで Web サイトが表示されます。

1. ブラウザプロセスが入力されたアドレスバーを元に HTML などのリソースのリクエストを行う
2. ブラウザプロセスがレスポンスのデータを解釈する
3. レンダラープロセスにデータを渡してページを表示する

それぞれのステップについて簡単に説明しましょう！

### 1. ブラウザプロセスが入力されたアドレスバーを元に HTML などのリソースのリクエストを行う

![URLが入力されたChromeのアドレスバー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164159/458bcb2f-3b3a-bb1a-973f-1c35c62fa855.png)

普段 Chrome を使うときにはアドレスバーに URL を入れて Web ページへアクセスすることもあるでしょう。
この **入力した URL を元にブラウザプロセスが通信を開始して HTML といったリソースを取得** しにいきます。

余談ですが、アドレスバーに入力するテキストには URL だけでなく Google 検索するキーワードの場合もあります。
ブラウザプロセスはこのような URL なのか検索キーワードなのかの判定もしています。

![キーワードが入力されたChromeのアドレスバー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164159/812c5f46-7016-24c9-d81e-27ee7cfc678c.png)

### 2. ブラウザプロセスがレスポンスのデータを解釈する

ユーザーがアドレスバーに入力した URL に対してリクエストを投げてレスポンスが返ってきました。
この **レスポンスが何者なのかを判定するのもブラウザプロセス** がやります。

![rakugo_hatena_chawan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164159/b79971a5-f135-c202-a0bc-8c48b38551f1.png)

レスポンスは HTML かもしれないですし、 zip かもしれません。
レスポンスのデータが何なのかを解釈した上で、レンダラープロセスにデータを渡して OK なのかを見るわけです。

また余談ですが、セキュリティ的にまずいサイトだった場合は警告を表示したり、あるいはレンダラープロセスにそもそもデータを渡さない、といったこともします。

### 3. レンダラープロセスにデータを渡してページを表示する

![present_girls.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164159/669a9fa0-dbdf-eb73-da10-b4ea5ef5f101.png)

ブラウザプロセスがアドレスバーに入力した URL に対するレスポンスデータの解釈が完了しました。
データを元に開いているタブ内で画面を表示したいですが、これはブラウザプロセスの役割ではありません。
**タブ内の画面表示はレンダラープロセスの役割** です。

ここで **ブラウザプロセスとレンダラープロセスとのコミュニケーションが発生** します。
ブラウザプロセスからレンダラープロセスに対してデータを渡して、レンダラープロセスがそのデータを元にタブ内の画面を表示をします。

## window.location で URL を変更すると何が起こるのか？

```javascript
window.location = "https://qiita.com/nuko-suke/items/a5bf4df00932b66847fc";
```

さて、 **冒頭で紹介したこのコードと今までお話したブラウザプロセスとレンダラープロセスのお話を紐づけることができます** 。

察しの良い方はもうわかるかもしれませんが、 **レンダラープロセスからブラウザプロセスへ「 URL を変更して別ページに遷移してね」と伝えている** のです。

![pet_kotoba_oshieru_oumu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164159/4bea74ed-918d-7580-a68c-4a541b94b611.png)

JavaScript の実行はレンダラープロセスで行われます。
`window.location = "URL"` のようにページ遷移を検出すると、ブラウザプロセスに対して「次この URL のページに遷移したいんだけど」と伝えます。

この後、ブラウザプロセスは「[ブラウザのアドレスバーに URL を入力するとどうなる？](#ブラウザのアドレスバーに-url-を入力するとどうなる)」でお話した通りの動きをします。
具体的には、新しい URL に対してリソースを取得したり、リソースの解析をしたり、などです。

１点、違う点としては **別のレンダラープロセスが立ち上がること** でしょう。
元々閲覧していたページとは別のレンダラープロセスに対して、ブラウザプロセスは新しいページの描画をお願いすることになります。

![5tThsmZamrpxFydJFePg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164159/671e7b72-4617-fb52-d799-ef8bce0e4beb.png)
([Inside look at modern web browser (part 2)](https://developer.chrome.com/blog/inside-browser-part2/) より引用)

## TIPS

本筋とは話が逸れますが、ブラウザプロセスとレンダラープロセスとのコミュニケーションは普段書いている JavaScript のイベントにも関わっています。

例えば `beforeunload` というイベントを例にあげましょう。

https://developer.mozilla.org/ja/docs/Web/API/Window/beforeunload_event

ユーザーがアドレスバーに別の URL を入力するケースを考えます。
この時、ブラウザプロセスがレンダラープロセスに対して「これからページ変わりますよ」と伝えます。
これがまさしく `beforeunload` イベントなわけです。

このように普段書いている JavaScript のイベントは実はブラウザプロセスとレンダラープロセスのコミュニケーションと深い関連があります。

## 最後に

いかがだったでしょうか。
普段何気なく書いている JavaScript が、裏ではブラウザが複数プロセスを立ち上げてコミュニケーションをとりながら動いているんですね。

その他、 `setTimeout` にも面白い秘密があったり、あまり知られていない Web API も紹介しているので、ぜひのぞいてみてください！

https://qiita.com/nuko-suke/items/5b16ab9de402547c5797

https://qiita.com/nuko-suke/items/c8c31ee34fd539805910

最後に、この記事を書くにあたっては次の Chrome Developers の記事が大変参考になりました。
もっと詳しく知りたい方はこちらの記事を読むことをおすすめします！

https://developer.chrome.com/blog/inside-browser-part1/

## 余談

ChatGPT にさらに聞いてみました。

![ChatGPTと追加のやりとり](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164159/d74d46ca-d775-d864-0818-6391eac88e07.png)

知っていましたね笑