6 瀏覽器對(duì)象
6.1 瀏覽器對(duì)象
6.1.1 JavaScript代碼嵌入網(wǎng)頁(yè)的方法
6.1.1.1 直接添加代碼塊
<script>
// some JavaScript code
</script>
6.1.1.2 加載外部腳本
<script src="example.js"></script>
6.1.1.3 行內(nèi)代碼
也可以在某些元素的事件屬性和a元素的href屬性中,直接寫(xiě)入JavaScript。
<div onclick="alert('Hello')"></div>
<a href="javascript:alert('Hello')"></a>
6.1.2 外部腳本的加載
6.1.2.1 網(wǎng)頁(yè)底部加載
網(wǎng)頁(yè)加載流程是這樣的:
- 瀏覽器開(kāi)始解析HTML網(wǎng)頁(yè)
- 解析過(guò)程中,發(fā)現(xiàn)script標(biāo)簽
- 暫停解析,下載script標(biāo)簽中的外部腳本
- 下載完成,執(zhí)行腳本
- 恢復(fù)往下解析HTML網(wǎng)頁(yè)
加載外部腳本,會(huì)暫停網(wǎng)頁(yè)執(zhí)行。因此建議將script標(biāo)簽放在頁(yè)面底部。這樣也避免了在DOM生成之前就調(diào)用DOM的錯(cuò)誤。
6.1.2.2 多個(gè)腳本的加載
多個(gè)腳本會(huì)同時(shí)平行下載,但是卻按出現(xiàn)順序執(zhí)行。
同一個(gè)域名的資源(腳本文件、樣式表文件、圖片文件),瀏覽器一般最多同時(shí)下載六個(gè)。如果是來(lái)自不同域名的資源,就沒(méi)有這個(gè)限制。所以,通常把靜態(tài)文件放在不同的域名之下,以加快下載速度。
6.1.2.3 defer屬性
給script增加defer屬性后,瀏覽器不阻塞頁(yè)面渲染,會(huì)繼續(xù)往下解析HTML網(wǎng)頁(yè),同時(shí)并行下載script標(biāo)簽中的外部腳本。待瀏覽器完成解析HTML網(wǎng)頁(yè),此時(shí)再執(zhí)行下載的腳本。
<script src="1.js" defer></script>
但是,有的瀏覽器可能不支持defer。
6.1.2.4 async屬性
給script增加async屬性后,瀏覽器不阻塞頁(yè)面渲染,會(huì)繼續(xù)往下解析HTML網(wǎng)頁(yè),同時(shí)并行下載script標(biāo)簽中的外部腳本。腳本下載完成,瀏覽器暫停解析HTML網(wǎng)頁(yè),開(kāi)始執(zhí)行下載的腳本。腳本執(zhí)行完畢,瀏覽器恢復(fù)解析HTML網(wǎng)頁(yè)。
<script src="1.js" async></script>
IE 10支持async屬性,低于這個(gè)版本的IE都不支持。
一般來(lái)說(shuō),如果腳本之間沒(méi)有依賴關(guān)系,就使用async屬性,如果腳本之間有依賴關(guān)系,就使用defer屬性。
6.1.2.5 腳本的動(dòng)態(tài)嵌入
除了用靜態(tài)的script標(biāo)簽,還可以動(dòng)態(tài)嵌入script標(biāo)簽。
['1.js', '2.js'].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
document.head.appendChild(script);
});
6.1.3 JavaScript虛擬機(jī)
javascript代碼被轉(zhuǎn)為字節(jié)碼后,并不能直接運(yùn)行,而是運(yùn)行在一個(gè)虛擬機(jī)(也叫JavaScript引擎)之上。
常見(jiàn)的JavaScript虛擬機(jī):
Chakra
V8
6.1.4 單線程模型
JavaScript采用單線程模型,原因是不想讓瀏覽器變得太復(fù)雜。
如果有一個(gè)任務(wù)特別耗時(shí),后面的任務(wù)都會(huì)等待,造成瀏覽器“假死”。其實(shí)這時(shí)候可以掛起處于等待中的任務(wù),先運(yùn)行排在后面的任務(wù)。這種機(jī)制就是JavaScript內(nèi)部采用的Event Loop。
6.1.5 Event Loop
所謂Event Loop,指的是一種內(nèi)部循環(huán),用來(lái)排列和處理事件,以及執(zhí)行函數(shù)。
6.1.6 任務(wù)隊(duì)列
如果有大量的異步任務(wù),它們會(huì)在“任務(wù)隊(duì)列”中注冊(cè)大量的事件。這些事件排成隊(duì)列,等候進(jìn)入主線程。
6.2 定時(shí)器
6.2.1 setTimeout
setTimeout函數(shù)指定過(guò)多少毫秒后執(zhí)行某個(gè)函數(shù)或某段代碼。
它返回定時(shí)器的編號(hào),以后可以用來(lái)取消這個(gè)定時(shí)器。
setTimeout('console.log(2)',1000);
setTimeout(f,1000);
setTimeout還允許添加更多的參數(shù):
setTimeout(function(a,b){
console.log(a+b);
},1000,1,1);
6.2.2 setInterval
setInterval函數(shù)指定循環(huán)(指的是“開(kāi)始執(zhí)行”之間的間隔)執(zhí)行某個(gè)函數(shù)或某段代碼。
<input type="button" onclick="clearInterval(timer)" value="stop">
function f(a){
console.log(a);
}
var timer = setInterval(f, 1000, "Hello World");
如果要實(shí)現(xiàn)固定間隔執(zhí)行代碼,不能用setInterval,而是每次執(zhí)行結(jié)束后,使用setTimeout指定下一次執(zhí)行的具體時(shí)間。
<input type="button" onclick="clearInterval(timer)" value="stop">
var timer = setTimeout(function() {
// do something
timer = setTimeout(arguments.callee, 2000);
}, 2000);
6.2.3 clearTimeout(),clearInterval()
用于取消相應(yīng)的計(jì)數(shù)器。
6.2.4 運(yùn)行機(jī)制
setTimeout和setInterval的運(yùn)行機(jī)制是,將指定的代碼移出本次執(zhí)行,等到下一輪Event Loop時(shí),再檢查是否到了指定時(shí)間。如果到了,就執(zhí)行對(duì)應(yīng)的代碼;如果不到,就等到再下一輪Event Loop時(shí)重新判斷。
每一輪Event Loop時(shí),都會(huì)將“任務(wù)隊(duì)列”中需要執(zhí)行的任務(wù),一次執(zhí)行完。setTimeout和setInterval都是把任務(wù)添加到“任務(wù)隊(duì)列”的尾部。因此,沒(méi)法保證,setTimeout和setInterval指定的任務(wù),一定會(huì)按照預(yù)定時(shí)間執(zhí)行。
6.2.5 setTimeout(f,0)
setTimeout(f,0)相當(dāng)于,一旦本次Event Loop完成就執(zhí)行。
0毫秒實(shí)際上達(dá)不到的。根據(jù)HTML 5標(biāo)準(zhǔn),setTimeOut推遲執(zhí)行的時(shí)間最少是4毫秒。
6.3 window對(duì)象
6.3.1 概述
JavaScript的所有對(duì)象都存在于一個(gè)運(yùn)行環(huán)境之中,這個(gè)運(yùn)行環(huán)境本身也是對(duì)象,稱為“頂層對(duì)象”。
在瀏覽器環(huán)境中,這個(gè)頂層對(duì)象就是window對(duì)象(w為小寫(xiě))。所有瀏覽器環(huán)境的全局變量,都是window對(duì)象的屬性。
6.3.2 window對(duì)象的屬性
6.3.2.1 window.name屬性
用于設(shè)置當(dāng)前瀏覽器窗口的名字(不是title)。瀏覽器刷新后,該屬性保持不變。
6.3.2.2 window.innerHeight屬性,window.innerWidth屬性
網(wǎng)頁(yè)的CSS布局占據(jù)的瀏覽器窗口的高度和寬度
6.3.2.3 window.pageXOffset屬性,window.pageYOffset屬性
頁(yè)面的水平/垂直滾動(dòng)距離
6.3.2.4 iframe元素
iframe元素遵守同源政策,只有當(dāng)父頁(yè)面與框架頁(yè)面來(lái)自同一個(gè)域名,兩者之間才可以用腳本通信
6.3.2.5 Navigator對(duì)象
Window對(duì)象的Navigator屬性是一個(gè)包含瀏覽器相關(guān)信息的對(duì)象。
1、Navigator.userAgent屬性
返回瀏覽器的User-Agent字符串,用來(lái)標(biāo)示瀏覽器的種類。
2、navigator.plugins屬性
返回一個(gè)類似數(shù)組的對(duì)象,成員是瀏覽器安裝的插件,比如Flash、ActiveX等。
6.3.2.6 screen對(duì)象
screen對(duì)象包含了顯示設(shè)備的信息。
screen.height // 1920
screen.width // 1080
可以根據(jù)屏幕分辨率,將用戶導(dǎo)向不同網(wǎng)頁(yè)。
6.3.3 window對(duì)象的方法
6.3.3.1 URL的編碼/解碼方法
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
6.3.4 window對(duì)象的事件
6.3.4.1 window.onerror
腳本發(fā)生錯(cuò)誤時(shí),會(huì)觸發(fā)window對(duì)象的error事件。我們可以通過(guò)window.onerror屬性對(duì)該事件指定回調(diào)函數(shù)。
6.3.4.2 alert(),prompt(),confirm()
alert 彈出的對(duì)話框,只有一個(gè)“確定”按鈕
prompt 彈出的對(duì)話框,在提示文字的下方,還有一個(gè)輸入框,要求用戶輸入信息,并有“確定”和“取消”兩個(gè)按鈕。
其返回值:字符串、空(或輸入框的默認(rèn)值)、或者null
var result = prompt('您的年齡?', 25) //25是默認(rèn)值,可無(wú)
confirm 彈出的對(duì)話框,除了提示信息之外,只有“確定”和“取消”兩個(gè)按鈕。
返回一個(gè)布爾值
var result = confirm("你最近好嗎?");
6.4 History對(duì)象
瀏覽器窗口有一個(gè)history對(duì)象,用來(lái)保存瀏覽歷史。
back():后退
forward():前進(jìn)
go():移動(dòng)到該整數(shù)指定的頁(yè)面,比如go(1)相當(dāng)于forward(),go(-1)相當(dāng)于back()。
6.5 Ajax
6.5.1 XMLHttpRequest對(duì)象
XMLHttpRequest對(duì)象用于從JavaScript發(fā)出HTTP請(qǐng)求,下面是典型用法。
// 新建一個(gè)XMLHttpRequest實(shí)例對(duì)象
var xhr = new XMLHttpRequest();
// 指定通信過(guò)程中狀態(tài)改變時(shí)的回調(diào)函數(shù)
xhr.onreadystatechange = function(){
// 通信成功時(shí),狀態(tài)值為4
var completed = 4;
if(xhr.readyState === completed){
if(xhr.status === 200){
// 處理服務(wù)器發(fā)送過(guò)來(lái)的數(shù)據(jù)
}else{
// 處理錯(cuò)誤
}
}
};
// open方式用于指定HTTP動(dòng)詞、請(qǐng)求的網(wǎng)址、是否異步
xhr.open('GET', '/endpoint', true);
// 發(fā)送HTTP請(qǐng)求
xhr.send(null);
6.5.1.1 Open()
open方法用于指定發(fā)送HTTP請(qǐng)求的參數(shù)
參數(shù)1,發(fā)送方法?!癎ET”、“POST”、“PUT”、“DELETE”
參數(shù)2,網(wǎng)址
參數(shù)3,是否異步
6.5.1.2 setRequestHeader()
setRequestHeader方法用于設(shè)置HTTP請(qǐng)求的頭信息。
6.5.1.3 send()
send方法用于實(shí)際發(fā)出HTTP請(qǐng)求。
不帶參數(shù),表示HTTP請(qǐng)求只包含頭信息,也就是只有URL,例如GET請(qǐng)求;
帶有參數(shù),表示還包含具體數(shù)據(jù)的信息體,例如POST請(qǐng)求。
send方法可以發(fā)送許多類型的數(shù)據(jù)。
void send();
void send(ArrayBuffer data);
void send(Blob data);//Blob類型可以用來(lái)發(fā)送二進(jìn)制數(shù)據(jù)(上傳文件)
void send(Document data);
void send(DOMString data);
void send(FormData data); //FormData類型可以用于構(gòu)造表單數(shù)據(jù)
6.5.1.4 readyState屬性和readyStateChange事件
每次狀態(tài)(readyState)變化是,都會(huì)觸發(fā)readyStateChange事件。
當(dāng)狀態(tài)變?yōu)?的時(shí)候,表示通信成功,這時(shí)就可以處理服務(wù)器傳送回來(lái)的數(shù)據(jù)。
6.5.1.5 progress事件
上傳文件時(shí),XMLHTTPRequest對(duì)象的upload屬性有一個(gè)progress,會(huì)不斷返回上傳的進(jìn)度。
6.5.1.6 服務(wù)器返回的信息
1、status屬性
表示返回的HTTP狀態(tài)碼。通信成功的狀態(tài)碼是200。
2、responseText屬性
表示服務(wù)器返回的文本數(shù)據(jù)。
6.5.1.7 setRequestHeader方法
用于設(shè)置HTTP頭信息。
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Content-Length', JSON.stringify(data).length);
xhr.send(JSON.stringify(data));
6.5.1.8 responseType屬性
用來(lái)指定服務(wù)器返回?cái)?shù)據(jù)(xhr.response)的類型。
'text':返回類型為字符串,這是默認(rèn)值。
'arraybuffer':返回類型為ArrayBuffer。
'blob':返回類型為Blob。
'document':返回類型為Document。
'json':返回類型為JSON object。
6.5.2 文件上傳
通常使用file控件實(shí)現(xiàn)文件上傳。
file控件的multiple屬性,指定可以一次選擇多個(gè)文件。
<input type="file" id="file-select" name="photos[]" multiple/>
file對(duì)象的files返回FileList對(duì)象,包含了用戶選中的文件。
var files = document.getElementById('file-select').files;
可以使用FormData接口上傳,也可以直接使用File API上傳。
6.5.3 JSONP
JSONP(JSON with Padding)是JSON的一種“使用模式”,可用于解決瀏覽器的跨域訪問(wèn)問(wèn)題。
但 script 元素調(diào)用js文件時(shí)則不受是否跨域的影響,利用這一點(diǎn),網(wǎng)頁(yè)可以得到從其他來(lái)源動(dòng)態(tài)產(chǎn)生的 JSON 資料,而這種使用模式就是所謂的 JSONP。
用 JSONP 抓到的資料并不是JSON,而是任意的JavaScript(因?yàn)镴SON不是合法的js語(yǔ)句,所以要將它放到一個(gè)回調(diào)方法里),用 JavaScript 直譯器執(zhí)行而不是用 JSON 解析器解析。
6.5.3.1 簡(jiǎn)單JSONP實(shí)現(xiàn)
客戶端代碼:
<script>
var localHandler = function(data){
alert(data.result);
};
</script>
<script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
服務(wù)器端代碼:
localHandler({"result":"1"});
6.5.3.2 服務(wù)器端動(dòng)態(tài)提供js腳本
客戶端代碼:
<script>
// 回調(diào)函數(shù)
var flightHandler = function(data){
alert('票價(jià) ' + data.price + ' 元,' + '余票 ' + data.tickets);
};
var url = "http://remoteserver.com/remote.aspx?code=CA1998&callback=flightHandler";
var script = document.createElement('script');
script.setAttribute('src', url);
document.getElementsByTagName('head')[0].appendChild(script);
</script>
服務(wù)器端代碼:
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
6.5.3.3 使用jQuery實(shí)現(xiàn)JSONP調(diào)用
客戶端代碼:
jQuery(document).ready(function(){
$.ajax({
type: "get",
async: false,
url: "http://remoteserver.com/remote.aspx?code=CA1998",
dataType: "jsonp",
jsonp: "callback",//傳遞給請(qǐng)求處理程序或頁(yè)面的,用以獲得jsonp回調(diào)函數(shù)名的參數(shù)名(一般默認(rèn)為:callback)
jsonpCallback:"flightHandler",//自定義的jsonp回調(diào)函數(shù)名稱,默認(rèn)為jQuery自動(dòng)生成的隨機(jī)函數(shù)名,也可以寫(xiě)"?",jQuery會(huì)自動(dòng)為你處理數(shù)據(jù)
success: function(json){
alert('票價(jià) ' + data.price + ' 元');
},
error: function(){
alert('fail');
}
});
});
6.5.4 CORS
CORS的全稱是“跨域資源共享”,它提出一種方法,允許JavaScript代碼向另一個(gè)域名發(fā)出XMLHttpRequests請(qǐng)求,從而克服了同域限制。
CORS機(jī)制與JSONP模式的使用目的相同,而且更強(qiáng)大。JSONP只支持GET請(qǐng)求,CORS可以支持所有類型的HTTP請(qǐng)求。
JSONP的優(yōu)勢(shì)在于可以用于老式瀏覽器,以及可以向不支持CORS的網(wǎng)站請(qǐng)求數(shù)據(jù)。
6.5.5 Fetch API
Fetch API是一種新興的規(guī)范,用來(lái)操作瀏覽器發(fā)出的網(wǎng)絡(luò)請(qǐng)求,目的是在將來(lái)取代XMLHttpRequest。
6.6 window.postMessage方法
window.postMessage方法就是用來(lái)在某種程度上,繞過(guò)同域限制,實(shí)現(xiàn)不同域名的窗口(包括iframe窗口)之間的通信。
6.7 Web Storage:瀏覽器端數(shù)據(jù)儲(chǔ)存機(jī)制
這個(gè)API用于在瀏覽器端儲(chǔ)存數(shù)據(jù)。它分成兩類:sessionStorage和localStorage。
它們很像cookie機(jī)制的強(qiáng)化版,能夠動(dòng)用大得多的存儲(chǔ)空間(Chrome是2.5MB)。另外,與cookie一樣,它們也受同域限制。
sessionStorage保存的數(shù)據(jù),當(dāng)會(huì)話結(jié)束時(shí)會(huì)被清空;
localStorage保存的數(shù)據(jù)長(zhǎng)期存在。
除了保存期限的長(zhǎng)短不同,這兩個(gè)對(duì)象的屬性和方法完全一樣。
6.8 IndexedDB:瀏覽器端數(shù)據(jù)庫(kù)
通俗地說(shuō),IndexedDB就是瀏覽器端數(shù)據(jù)庫(kù)。
IndexedDB不屬于關(guān)系型數(shù)據(jù)庫(kù)(不支持SQL),更接近NoSQL數(shù)據(jù)庫(kù)。
IndexedDB的下特點(diǎn):
1、鍵值對(duì)儲(chǔ)存。
2、異步。 IndexedDB操作時(shí)不會(huì)鎖死瀏覽器。
3、支持事務(wù)。IndexedDB支持事務(wù)。
4、同域限制 每個(gè)數(shù)據(jù)庫(kù)對(duì)應(yīng)創(chuàng)建該數(shù)據(jù)庫(kù)的域名。
5、儲(chǔ)存空間大 一般來(lái)說(shuō)不少于250MB。
6、支持二進(jìn)制儲(chǔ)存。
6.9 Web Notification API
Notification API是瀏覽器的通知接口,用于在用戶的桌面顯示通知信息。
具體的實(shí)現(xiàn)形式由瀏覽器自行部署,對(duì)于手機(jī)來(lái)說(shuō),一般顯示在頂部的通知欄。
6.10 Performance API
Performance API用于精確度量、控制、增強(qiáng)瀏覽器的性能表現(xiàn)。
6.11 移動(dòng)設(shè)備API
HTML 5推出了一系列針對(duì)移動(dòng)設(shè)備的API。
比如獲取顯示區(qū)域、地理信息、震動(dòng)手機(jī)、屏幕亮度、手機(jī)擺放方向等。
6.12 WebRTC
WebRTC是“網(wǎng)絡(luò)實(shí)時(shí)通信”(Web Real Time Communication)的縮寫(xiě)。它最初是為了解決瀏覽器上視頻通話而提出的,即兩個(gè)瀏覽器之間直接進(jìn)行視頻和音頻的通信,不經(jīng)過(guò)服務(wù)器。后來(lái)發(fā)展到除了音頻和視頻,還可以傳輸文字和其他數(shù)據(jù)。