前面的話
一般地,使用readystatechange事件探測HTTP請求的完成。XHR2規范草案定義了進度事件Progress Events規范,XMLHttpRequest對象在請求的不同階段觸發不同類型的事件,所以它不再需要檢査readyState屬性。這個草案定義了與客戶端服務器通信有關的事件。這些事件最早其實只針對XHR操作,但目前也被其他API(如File API)借鑒。本文將詳細介紹進度事件
?
基礎
有以下6個進度事件
loadstart:在接收到響應數據的第一個字節時觸發
progress:在接收響應期間持續不斷地觸
error:在請求發生錯誤時觸發
abort:在因為調用abort()方法而終止連接時觸發
load:在接收到完整的響應數據時觸發
loadend:在通信完成或者觸發error、abort或load事件后觸發
timeout:超時發生時觸發
[注意]IE9-瀏覽器不支持以上事件(IE9瀏覽器僅支持load事件)
每個請求都從觸發loadstart事件開始,接下來,通常每隔50毫秒左右觸發一次progress事件,然后觸發load、error、abort或timeout事件中的一個,最后以觸發loadend事件結束
對于任何具體請求,瀏覽器將只會觸發load、abort、timeout和error事件中的一個。XHR2規范草案指出一旦這些事件中的一個發生后,瀏覽器應該觸發loadend事件
?
load
響應接收完畢后將觸發load事件,因此也就沒有必要去檢查readyState屬性了。但一個完成的請求不一定是成功的請求,例如,load事件的處理程序應該檢查XMLHttpRequest對象的status狀態碼來確定收到的是“200 OK”而不是“404 Not Found”的HTTP響應
<button id="btn">獲取信息</button> <div id="result"></div> <script> btn.onclick = function(){//創建xhr對象var xhr;if(window.XMLHttpRequest){xhr = new XMLHttpRequest();}else{xhr = new ActiveXObject('Microsoft.XMLHTTP');}//進度事件xhr.onload = function(){if(xhr.status == 200){result.innerHTML += xhr.responseText;}}//發送請求xhr.open('get','message.xml',true);xhr.send(); } </script>
progress
progress事件會在瀏覽器接收新數據期間周期性地觸發。而onprogress事件處理程序會接收到一個event對象,其target屬性是XHR對象,但包含著三個額外的屬性:lengthComputable、loaded和total。其中,lengthComputable是一個表示進度信息是否可用的布爾值,loaded表示已經接收的字節數,total表示根據Content-Length響應頭部確定的預期字節數。有了這些信息,就可以為用戶創建一個進度指示器了
<button id="btn">獲取信息</button> <div id="result"></div> <div id="music"></div> <script> btn.onclick = function(){//創建xhr對象var xhr;if(window.XMLHttpRequest){xhr = new XMLHttpRequest();}else{xhr = new ActiveXObject('Microsoft.XMLHTTP');}//進度事件xhr.onprogress = function(e){e = e || event;if (e.lengthComputable){result.innerHTML = "Received " + e.loaded + " of " + e.total + " bytes";}};xhr.onload = function(e){var data = xhr.response;e = e || event;if(xhr.status == 200){var audio = document.createElement('audio');audio.onload = function(){URL.revokeObjectURL(audio.src);}audio.src = URL.createObjectURL(data);console.log(audio);audio.setAttribute('controls','');if(!music.innerHTML){music.appendChild(audio);}}};//發送請求xhr.open('get','myocean.mp3',true);xhr.responseType = 'blob';xhr.send(); } </script>
上傳進度
除了為監控HTTP響應的加載定義的這些有用的事件外,XHR2也給出了用于監控HTTP請求上傳的事件。在實現這些特性的瀏覽器中,XMLHttpRequest對象將有upload屬性。upload屬性值是一個對象,它定義了addEventListener()方法和整個progress事件集合,比如onprogress和onload(但upload對象沒有定義onreadystatechange屬性,upload僅能觸發新的事件類型)
能僅僅像使用常見的progress事件處理程序一樣使用upload事件處理程序。對于XMLHttpRequest對象,設置XHR.onprogress以監控響應的下載進度,并且設置XHR.upload.onprogress以監控請求的上傳進度
<input type="file" name="file1" id="file1" style="display:none"> <button id="btn">上傳文件</button> <div id="pro"></div> <div id="result"></div> <script> btn.onclick = function(){file1.click();pro.innerHTML = result.innerHTML = ''; } file1.onchange = function(){//創建xhr對象var xhr;if(window.XMLHttpRequest){xhr = new XMLHttpRequest();}else{xhr = new ActiveXObject('Microsoft.XMLHTTP');}var data = file1.files[0];//上傳事件xhr.upload.onprogress = function(e){e = e || event;if (e.lengthComputable){pro.innerHTML = "上傳進度為:" + e.loaded + " of " + e.total + " bytes" + ';百分比為:' + e.loaded/e.total;}}xhr.onload = function(e){var data = xhr.responseText;e = e || event;if(xhr.status == 200){result.innerHTML = data;}};//發送請求xhr.open('post','pp.php',true);xhr.setRequestHeader("content-type",data.type);xhr.send(data); } </script>
<?php error_reporting(E_ALL & ~E_NOTICE); touch($file); if(preg_match('/image/',apache_request_headers()['content-type'])){$file = 'photo/test.jpg'; binary_to_file($file);echo '文件上傳成功!'; }else{echo '文件格式不正確,請選擇圖片文件'; } function binary_to_file($file){$content = $GLOBALS['HTTP_RAW_POST_DATA']; // 需要php.ini設置if(empty($content)){$content = file_get_contents('php://input'); //不需要php.ini設置,內存壓力小}$ret = file_put_contents($file, $content, true);return $ret; }; ?>
?
其他事件
HTTP請求無法完成有3種情況,對應3種事件。如果請求超時,會觸發timeout事件。如果請求中止,會觸發abort事件。最后,像太多重定向這樣的網絡錯誤會阻止請求完成,但這些情況發生時會觸發error事件
可以通過調用XMLHttpRequest對象的abort()方法來取消正在進行的HTTP請求。調用abort()方法在這個對象上觸發abort事件
調用abort()的主要原因是完成取消或超時請求消耗的時間太長或當響應變得無關時。假如使用XMLHttpRequest為文本輸入域請求自動完成推薦。如果用戶在服務器的建議達到之前輸入了新字符,這時等待請求不再有用,應該中止
XHR對象的timeout屬性等于一個整數,表示多少毫秒后,如果請求仍然沒有得到結果,就會自動終止。該屬性默認等于0,表示沒有時間限制
如果請求超時,將觸發ontimeout事件
var xhr = new XMLHttpRequest(); btn.onclick = function(){xhr.abort(); }; xhr.ontimeout = function(){console.log('The request timed out.'); } xhr.timeout = 100; xhr.onabort = function(){console.log("The transfer has been canceled by the user."); } xhr.onerror = function(){console.log("An error occurred while transferring the file."); } xhr.onloadend = function(){console.log("請求結束"); }