每隔一段時間去看以前的東西,都會有不一樣的心得,尤其是看似基本卻很重要的觀念。
用比較 old style 的說法就是:見山是山,見山不是山,見山還是山(以前學生時期很常被老師校長拿來講的…呵呵)

大致流程

完整的流程其實翻開計算機網路的課本會比較詳細,不過這邊還是列出大致的流程。

  1. 客戶端(Client/browser)
    使用者會先打開客戶端,例如瀏覽器。

  2. 查詢 IP 位置(look up domain table)
    !{}(https://wpsupportdesk.com/wp-content/uploads/2019/11/domin_and_ipaddress.png)
    很多人以為第二步馬上就是送出請求,其實並不是,要送出請求之前一定會先找位置,會根據使用者輸入的 domain name 查詢 IP。
    所以會先從能長的地方都盡可能地找,例如:瀏覽器, OS, cache…。

  3. 請求(http request)
    有位置之後瀏覽器就可以開始請求了,如果你好奇瀏覽器送出的請求帶什麼資料,你可以去 google.com 打開 Network 查看
    瀏覽器會自動夾帶一些 Request headers 到後端去,例如:cookies。

  4. 後端(Server)
    後端收到請求之後會開始產生前端所需要的資料。

  5. 回傳(Response)

前端執行流程

以前傳統都是後端會回傳 HTML 給瀏覽器,但是如果是現代前端開發的話,則是會在瀏覽器進行畫面互動處理。

Create react app 為例

讓我們回來最初的原點,產生專案的開始。

一開始我們專案上的 index.html 長這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

不過如果打包過後,會把一些必要的資源給加上去。
特別是在 body 最底下,你會發現突然多出了一些 chunk script。
之所以打包軟體會把 script 放到最底下也是因為避免發生 render blocking 的狀況(後面會再提到)
而且不允許同時下載兩個 script:
The HTTP specification defines that browsers should not download more than two components in parallel.

基本上執行順序為:當瀏覽器解析 DOM 的時候,通常會先分析 head 再來是 body。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="./logo.JPG" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<title>...</title>
<link href="/static/css/2.7fc9bc2b.chunk.css" rel="stylesheet" />
<link href="/static/css/main.50a29fa1.chunk.css" rel="stylesheet" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script>
!(function (e) {
// 省略
})([]);
</script>
<script src="/static/js/2.e0abf644.chunk.js"></script>
<script src="/static/js/main.0e562530.chunk.js"></script>
</body>
</html>

head 裡面我們通常會放置一些比較單純的資訊或是外部資源,例如:title, metadata…。
通常我們不會把 loading 太大的資源放在 head,不然會造成 render blocking,甚至會嚴重影響到 SEO。
因此這邊我們通常會放與畫面相關或是一些必要的資源。
關於外部資源的介紹可以參考這裡,我們也會利用一些小技巧來優化資源載入,例如 preload。

例子

1
2
3
4
5
6
7
8
9
10
<!-- index.html -->
<html>
<head>
<title>My Page</title>
<script src="my-script.js"></script>
</head>
<body>
<div id="user-greeting">Welcome back, user</div>
</body>
</html>
1
2
3
4
5
// my-script.js
document.addEventListener("DOMContentLoaded", function () {
// this function runs when the DOM is ready, i.e. when the document has been parsed
document.getElementById("user-greeting").textContent = "Welcome back, Bart";
});

body

head 讀取完之後,再來就會開始讀取 body 內的 DOM。
root div 會先畫,再來解析後面的 script。

操作 DOM

因為畫面的結構已經在上方的 body 呈現了,所以如果想要設計 script 來操作 DOM 互動,就可以寫在下方。

CSS in JS

目前比較提倡 script 能盡量放 body 最下面就放那邊,你也會發現打包軟體或是前端的框架也是這樣做。
例如:emotion 的 styled-component 就是在要用到特定的 style 的時候,再把特定的 style 放到某個 DOM 之前。

1
2
3
4
5
6
7
<style data-emotion="css hh3vd8">
.css-hh3vd8 {
color: #86868b;
margin-top: 6px;
}
</style>
<p class="css-hh3vd8 eeslu2o3">test</p>

事件處理

當瀏覽器解析完 DOM 之後,也代表網頁的初始樣貌已經渲染完成了
再來剩下的就是根據使用者的操作進行事件處理了

參考資料

https://stackoverflow.com/questions/436411/where-should-i-put-script-tags-in-html-markup


Comment