事跟我說(shuō)他用jQuery取不到頁(yè)面上隱藏元素input的值,他的html頁(yè)面大概內(nèi)容如下。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="jslib/jquery-1.11.2.min.js"></script>
<title>淺談Html頁(yè)面內(nèi)容執(zhí)行順序</title>
<script type="text/javascript">
var userId = $('#hiddenUserId').val();
var contextPath = $('#hiddenContextPath').val();
var userName = $('#hiddenUserName').val();
</script>
</head>
<body>
<input type="hidden" id="hiddenUserId" value="101" />
<input type="hidden" id="hiddenContextPath" value="/web" />
<input type="hidden" id="hiddenUserName" value="小明" />
</body>
</html>
頁(yè)面中的JS腳本在head中,JS腳本要讀取的input在body中。瀏覽器對(duì)html頁(yè)面內(nèi)容的加載是順序加載,也就是在html頁(yè)面中前面先加載,因此當(dāng)加載到JS腳本時(shí),input還沒(méi)有加載到瀏覽器中。JS是一種解釋性的腳本,也是從上而下順序執(zhí)行,由于這段JS代碼是立即執(zhí)行的,所以當(dāng)JS在執(zhí)行的時(shí)候,讀取不到input的值。
最直接的修改方法是把JS放到網(wǎng)頁(yè)的最下面執(zhí)行。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="jslib/jquery-1.11.2.min.js"></script>
<title>淺談Html頁(yè)面內(nèi)容執(zhí)行順序</title>
</head>
<body>
<input type="hidden" id="hiddenUserId" value="101" />
<input type="hidden" id="hiddenContextPath" value="/web" />
<input type="hidden" id="hiddenUserName" value="小明" />
<script type="text/javascript">
var userId = $('#hiddenUserId').val();
var contextPath = $('#hiddenContextPath').val();
var userName = $('#hiddenUserName').val();
</script>
</body>
</html>
把JS放到網(wǎng)頁(yè)的最下面,這樣在JS執(zhí)行的時(shí)候,網(wǎng)頁(yè)內(nèi)容都已經(jīng)加載完畢。把JS放在網(wǎng)頁(yè)的最下面方法并不是最好的解決方法,大部分情況JS并不是總能放在網(wǎng)頁(yè)的最下面。這時(shí)可以用window的onload事件,onload事件在整個(gè)頁(yè)面都加載完成后才觸發(fā),可以把JS腳本放在onload里面執(zhí)行。不同瀏覽器onload事件添加方式也不一樣。
IE下事件:
window.attachEvent('onload', function(){
var userId = $('#hiddenUserId').val();
var contextPath = $('#hiddenContextPath').val();
var userName = $('#hiddenUserName').val();
});
Chrome/Firefox等DOM標(biāo)準(zhǔn)事件:
window.addEventListener('load', function(){
var userId = $('#hiddenUserId').val();
var contextPath = $('#hiddenContextPath').val();
var userName = $('#hiddenUserName').val();
});
由于不同瀏覽器的事件添加方式不一樣,jQuery為我們提供了通用的初始化方法,該方法在頁(yè)面加載完成時(shí)觸發(fā)。
$(function(){
var userId = $('#hiddenUserId').val();
var contextPath = $('#hiddenContextPath').val();
var userName = $('#hiddenUserName').val();
});
上面方法本質(zhì)就是添加onload監(jiān)聽(tīng)事件。
最終修改后的頁(yè)面
SS加載存在先后順序,不嚴(yán)謹(jǐn)?shù)臅?shū)寫(xiě)順序?qū)?huì)導(dǎo)致界面出現(xiàn)偏差。并且正確的書(shū)寫(xiě)順序也可以提高代碼的可讀性。
正確的排序方式如下:
(1)定位屬性:position display float left top right bottom overflow clear z-index flex
(2)自身屬性:width height padding border margin background
(3)文字屬性:font-famliy font-size font-style font-weight font-varient color
(4)文本屬性:text-align vertical-align text-wrap text-transform text-indent text-ecoration letter-spacing white-spacing white-space text-overflow
(5)CSS3中新增屬性:content box-shadow border-radius transform……
css順序按照以上順序書(shū)寫(xiě)即可。
<h4 id="目的減少瀏覽器的reflow回流提高瀏覽器加載速度">目的:減少瀏覽器的reflow(回流),提高瀏覽器加載速度
接下來(lái)講解瀏覽器的渲染原理
瀏覽器引擎簡(jiǎn)介
瀏覽器——Firefox、Chrome和Safari是基于兩種渲染引擎構(gòu)建的,F(xiàn)irefox使用Geoko——Mozilla自主研發(fā)的渲染引擎,Safari和Chrome都使用webkit。
渲染主流程
渲染引擎首先通過(guò)網(wǎng)絡(luò)獲得所請(qǐng)求文檔的內(nèi)容,通常以8K分塊的方式完成。下面是渲染引擎在取得內(nèi)容之后的基本流程:
①解析html以構(gòu)建dom樹(shù) -> ②構(gòu)建render樹(shù) -> ③布局render樹(shù) -> ④繪制render樹(shù)
css樣式解析到顯示至瀏覽器屏幕上就發(fā)生在②③④步驟,可見(jiàn)瀏覽器并不是一獲取到css樣式就立馬開(kāi)始解析而是根據(jù)css樣式的書(shū)寫(xiě)順序?qū)⒅凑誨om樹(shù)的結(jié)構(gòu)分布render樣式,完成第②步,然后開(kāi)始遍歷每個(gè)樹(shù)結(jié)點(diǎn)的css樣式進(jìn)行解析,此時(shí)的css樣式的遍歷順序完全是按照之前的書(shū)寫(xiě)順序。在解析過(guò)程中,一旦瀏覽器發(fā)現(xiàn)某個(gè)元素的定位變化影響布局,則需要倒回去重新渲染。
概念:
DOM Tree:瀏覽器將HTML解析成樹(shù)形的數(shù)據(jù)結(jié)構(gòu)。
CSS Rule Tree:瀏覽器將CSS解析成樹(shù)形的數(shù)據(jù)結(jié)構(gòu)。
Render Tree: DOM和CSSOM合并后生成Render Tree。
layout: 有了Render Tree,瀏覽器已經(jīng)能知道網(wǎng)頁(yè)中有哪些節(jié)點(diǎn)、各個(gè)節(jié)點(diǎn)的CSS定義以及他們的從屬關(guān)系,從而去計(jì)算出每個(gè)節(jié)點(diǎn)在屏幕中的位置。
painting: 按照算出來(lái)的規(guī)則,通過(guò)顯卡,把內(nèi)容畫(huà)到屏幕上。
reflow(回流):當(dāng)瀏覽器發(fā)現(xiàn)某個(gè)部分發(fā)生了點(diǎn)變化影響了布局,需要倒回去重新渲染,內(nèi)行稱(chēng)這個(gè)回退的過(guò)程叫reflow。reflow會(huì)從 (html)根節(jié)點(diǎn) 這個(gè)root frame開(kāi)始遞歸往下,依次計(jì)算所有的結(jié)點(diǎn)幾何尺寸和位置。reflow幾乎是無(wú)法避免的。
repaint(重繪):改變某個(gè)元素的背景色、文字顏色、邊框顏色等等不影響它周?chē)騼?nèi)部布局的屬性時(shí),屏幕的一部分要重畫(huà),但是元素的幾何尺寸沒(méi)有變。
例如:現(xiàn)在界面上流行的一些效果,比如樹(shù)狀目錄的折疊、展開(kāi)(實(shí)質(zhì)上是元素的顯 示與隱藏)等,都將引起瀏覽器的 reflow。鼠標(biāo)滑過(guò)、點(diǎn)擊……只要這些行為引起了頁(yè)面上某些元素的占位面積、定位方式、邊距等屬性的變化,都會(huì)引起它內(nèi)部、周?chē)踔琳麄€(gè)頁(yè)面的重新渲染。
注意:
(1)display:none 的節(jié)點(diǎn)不會(huì)被加入Render Tree,而visibility: hidden 則會(huì),所以,如果某個(gè)節(jié)點(diǎn)最開(kāi)始是不顯示的,設(shè)為display:none是更優(yōu)的。
(2)display:none 會(huì)觸發(fā) reflow,而 visibility:hidden 只會(huì)觸發(fā) repaint,因?yàn)闆](méi)有發(fā)現(xiàn)位置變化。
(3)有些情況下,比如修改了元素的樣式,瀏覽器并不會(huì)立刻reflow 或 repaint 一次,而是會(huì)把這樣的操作積攢一批,然后做一次 reflow,這又叫異步 reflow 或增量異步 reflow。但是在有些情況下,比如resize 窗口,改變了頁(yè)面默認(rèn)的字體等。對(duì)于這些操作,瀏覽器會(huì)馬上進(jìn)行 reflow。
覽器的工作機(jī)制,一句話(huà)概括起來(lái)就是:web瀏覽器與web服務(wù)器之間通過(guò)HTTP協(xié)議進(jìn)行通信的過(guò)程。所以,C/S之間握手的協(xié)議就是HTTP協(xié)議。瀏覽器接收完畢開(kāi)始渲染之前大致過(guò)程如下:
從瀏覽器地址欄的請(qǐng)求鏈接開(kāi)始,瀏覽器通過(guò)DNS解析查到域名映射的IP地址,成功之后瀏覽器端向此IP地址取得連接,成功連接之后,瀏覽器端將請(qǐng) 求頭信息 通過(guò)HTTP協(xié)議向此IP地址所在服務(wù)器發(fā)起請(qǐng)求,服務(wù)器接受到請(qǐng)求之后等待處理,最后向?yàn)g覽器端發(fā)回響應(yīng),此時(shí)在HTTP協(xié)議下,瀏覽器從服務(wù)器接收到 text/html類(lèi)型的代碼,瀏覽器開(kāi)始顯示此html,并獲取其中內(nèi)嵌資源地址,然后瀏覽器再發(fā)起請(qǐng)求來(lái)獲取這些資源,并在瀏覽器的html中顯示。
離我們最近并能直接顯示一個(gè)完整通信過(guò)程的工具就是Firebug了,看下圖:
其中黃色的tips浮層告訴了我們”colorBox.html”從發(fā)起請(qǐng)求到關(guān)閉連接整個(gè)過(guò)程中每個(gè)環(huán)節(jié)的時(shí)長(zhǎng)(域名解析 -> 建立連接 -> 發(fā)起請(qǐng)求 -> 等待響應(yīng) -> 接收數(shù)據(jù)),點(diǎn)擊該請(qǐng)求,可以獲得HTTP的headers信息,包含響應(yīng)頭信息與請(qǐng)求頭信息,如:
//響應(yīng)頭信息 HTTP/1.1 304
Server: Apache/2.2.4 (Win32) PHP/5.2.1 Connection: Keep-Alive Keep-Alive: timeout=5, max=100 Etag: "1e483-1324-a86f5621"
//請(qǐng)求頭信息 GET /Docs/eva/api/colorBox.html HTTP/1.1 Host: ued.com User-Agent: Mozilla/5.0
Firefox/3.6.13 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive Referer: http://ued.com/Docs/ If-Modified-Since: Thu, 17 Feb 2011 10:14:07 GMT If-None-Match: "1e483-1324-a86f5621" Cache-Control: max-age=0
另外,ajax異步請(qǐng)求同樣遵循HTTP協(xié)議,原理大同小異。
瀏覽器加載顯示html頁(yè)面內(nèi)容的順序
我們經(jīng)常看到瀏覽器在加載某個(gè)頁(yè)面時(shí),部分內(nèi)容先顯示出來(lái),又有些內(nèi)容后顯示。那么瀏覽器加載顯示html究竟是按什么順序進(jìn)行的呢?
其實(shí)瀏覽器加載顯示html的順序是按下面的順序進(jìn)行的:
1、IE下載的順序是從上到下,渲染的順序也是從上到下,下載和渲染是同時(shí)進(jìn)行的。
2、在渲染到頁(yè)面的某一部分時(shí),其上面的所有部分都已經(jīng)下載完成(并不是說(shuō)所有相關(guān)聯(lián)的元素都已經(jīng)下載完)。
3、如果遇到語(yǔ)義解釋性的標(biāo)簽嵌入文件(JS腳本,CSS 劍 敲創(chuàng)聳盜E的下載過(guò)程會(huì)啟用單獨(dú)連接進(jìn)行下載。
4、并且在下載后進(jìn)行解析,解析過(guò)程中,停止頁(yè)面所有往下元素的下載。
5、樣式表在下載完成后,將和以前下載的所有樣式表一起進(jìn)行解析,解析完成后,將對(duì)此前所有元素(含以前已經(jīng)渲染的)重新進(jìn)行渲染。
6、JS、CSS中如有重定義,后定義函數(shù)將覆蓋前定義函數(shù)。
Firefox處理下載和渲染順序大體相同,只是在細(xì)微之處有些差別,例如:iframe的渲染
如果你的網(wǎng)頁(yè)比較大,希望部分內(nèi)容先顯示出來(lái),粘住瀏覽者,那么你可以按照上面的規(guī)則合理的布局你的網(wǎng)頁(yè),達(dá)到預(yù)期的目的。
JS的加載
不能并行下載和解析(阻塞下載)
當(dāng) 引用了JS的時(shí)候,瀏覽器發(fā)送1個(gè)jsrequest就會(huì)一直等待該request的返回。因?yàn)闉g覽器需要1個(gè)穩(wěn)定的DOM樹(shù)結(jié)構(gòu),而JS中很有可能有代 碼直接改變了DOM樹(shù)結(jié)構(gòu),比如使用 document.write 或 appendChild,甚至是直接使用的location.href進(jìn)行跳轉(zhuǎn),瀏覽器為了防止出現(xiàn)JS修改DOM樹(shù),需要重新構(gòu)建DOM樹(shù)的情況,所以 就會(huì)阻塞其他的下載和呈現(xiàn).
為了更清楚的顯示頁(yè)面元素的加載順序,動(dòng)手寫(xiě)了一個(gè)程序,程序?qū)?yè)面中的每個(gè)元素都延遲10秒。
程序的位置在見(jiàn)附件。
首先查看TestHtmlOrder.aspx這個(gè)頁(yè)面,使用HttpWatcher來(lái)檢測(cè)頁(yè)面元素的加載。
從下面的圖中可以看到加載順序。
IE首先加載了主頁(yè)面TestHtmlOrder.aspx,
下載了主頁(yè)面后,頁(yè)面首先顯示的是“紅色劍靈”、“藍(lán)色劍靈”幾個(gè)字,但此時(shí)顯示的是只是黑色字體,沒(méi)有樣式,因?yàn)闃邮竭€沒(méi)有下載下來(lái)。
接下來(lái)頁(yè)面中的標(biāo)簽是JS標(biāo)簽,屬于嵌入文件,因此IE需要將其下載下來(lái)。這有兩個(gè)文件,雖然IE同時(shí)能夠和WebServer建立兩個(gè)鏈接,但是此時(shí)并沒(méi)有使用兩個(gè)連接,而是使用一個(gè)連接,在下載完成后,接下來(lái)才下載另外一個(gè)文件。
究其原因,是因?yàn)镴S包含了語(yǔ)法定義,在第二個(gè)文件里面的函數(shù)可能用到了第一個(gè)文件里面的變量和函數(shù),IE沒(méi)有辦法判斷,或者需要很耗時(shí)的判斷,才 能判斷文件下載的先后順序。而在解釋方面,IE對(duì)JS文件是下載一個(gè),解釋一個(gè)(可以執(zhí)行文件TestJsOrder2.aspx)。如果先下載的是第二 個(gè)文件,此時(shí)就會(huì)發(fā)生解釋錯(cuò)誤。因此需要開(kāi)發(fā)者自己在放置JS文件位置時(shí),按先后順序放好,IE依次下載進(jìn)行解釋。后面的函數(shù)覆蓋前面的函數(shù)定義
在下載完成后,我們看到helloWorld,helloworld2,開(kāi)始順序執(zhí)行。而此時(shí)字體的樣式表和圖片仍然沒(méi)有下載下來(lái)。
在helloWorld,helloWorld2執(zhí)行過(guò)程時(shí),此時(shí)頁(yè)面停留在函數(shù)執(zhí)行的中斷點(diǎn)(alert部分)。此時(shí)IE并沒(méi)有去下載CSS的文件。由此說(shuō)明JS函數(shù)的執(zhí)行會(huì)阻塞IE的下載。
接下來(lái)我們看到CSS文件的下載也是使用了一個(gè)連接,也是串行下載。其串行下載的原因和JS串行下載原因是一樣的。
在兩個(gè)CSS文件下載過(guò)程中,我們看到“紅色劍靈”,“藍(lán)色劍靈”依次變?yōu)榧t色和藍(lán)色,兩者顏色的轉(zhuǎn)換時(shí)間相差在10秒,說(shuō)明樣式文件和JS文件一樣是下載完一個(gè)解析一個(gè)的。
現(xiàn)在轉(zhuǎn)到TestCssOrder.aspx看一下,可以看到 開(kāi)始時(shí)“紅色劍靈”,“紅色強(qiáng)壯劍靈”,顯示為紅色,過(guò)了10秒“藍(lán)色劍靈”顯示為藍(lán)色,再過(guò)10秒,“紅色強(qiáng)壯劍靈”字體變粗了,同時(shí)“紅色強(qiáng)壯劍靈 2”開(kāi)始出現(xiàn)。在剛開(kāi)始“紅色劍靈”,“紅色強(qiáng)壯劍靈”顯示紅色時(shí),第三個(gè)樣式還沒(méi)有下載下來(lái),此時(shí)IE使用已經(jīng)下載到樣式對(duì)上面的元素渲染了一遍,此時(shí) 雖然“紅色劍靈”,“紅色強(qiáng)壯劍靈”樣式定義不同,但是顯示效果一樣。第三個(gè)文件下載后,此時(shí)IE又重新對(duì)“紅色強(qiáng)壯劍靈”渲染了一遍,此時(shí)其變?yōu)榧哟郑?以上所有的文件加載并且渲染完成后,開(kāi)始渲染下面的標(biāo)簽“紅色強(qiáng)壯劍靈2”
有一點(diǎn)需要證明:在IE使用樣式對(duì)標(biāo)簽進(jìn)行渲染時(shí),是不是停止了其他頁(yè)面元素的下載?原來(lái)我想通過(guò)加長(zhǎng)渲染時(shí)間(利用濾鏡,將標(biāo)簽元素?cái)?shù)目增大)來(lái)檢測(cè),不過(guò)沒(méi)有驗(yàn)證成功。只是從JS函數(shù)的執(zhí)行推斷CSS的渲染也是如此。
接下來(lái)看到的是圖片文件下載,此時(shí)看到的是兩個(gè)圖片同時(shí)開(kāi)始下載,而且是下載完成后,立即在頁(yè)面上開(kāi)始顯示,直到所有的圖片下載完成。
注:一個(gè)測(cè)試文件在網(wǎng)絡(luò)傳輸上所花費(fèi)時(shí)間的辦法。
首先需要明白檢測(cè)中w ait值的意義:wait = 服務(wù)器所花時(shí)間 + 網(wǎng)絡(luò)時(shí)間
服務(wù)器所花時(shí)間我們可以用Thread.Sleep(10000);來(lái)讓其休息10s,
比如這個(gè):
由此大概可以計(jì)算出 10.002-10 = 0.002秒,這就是大概在網(wǎng)絡(luò)上所花的時(shí)間。
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。