前端培訓-初級階段-場景實戰(2019-06-06)-下載文件&下載進度

前端最基礎的就是 HTML+CSS+Javascript。掌握了這三門技術就算入門,但也僅僅是入門,如今前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS),本着提高技術水平,打牢基礎知識的中心思想,咱們開課啦(每週四)。html

這兩天,碰到了不止一次前端下載的的問題。其實以前我寫過一篇文章 download使用淺析,主要依靠 download 屬性來實現瀏覽器端下載,由於是走瀏覽器的下載,因此沒有進度條。今天咱們就來講說個人解決方案。前端

  1. sf 的一個問題,須要顯示進度條。答案地址問題地址
  2. 一個朋友的問題,下載的文件須要 headers 驗證,無奈只能 ajax 拿數據,可是拉回來的仍是字符串,須要本身處理。
  3. 一個朋友的問題,監測下載進度。

今天咱們要講什麼?

  1. 如何使用 download 屬性,下載文件。
    這節主要是講如何使用,以及前端下載的核心操做。
  2. 下載文件,並顯示進度條。
    這節是正常操做,若是你只爲了解原理,看到這裏就夠了
  3. 其餘數據類型如何互相轉換
    這節就不同了。由於以前的 api 是使用 blob 實現,可是 ajax 傳回來的數據有好多種類型,咱們如何將他們相互轉換?

如何使用 download 屬性,下載文件。

download使用淺析 這一文中已經介紹了,能夠去看看。我這裏簡單說一下。<a>標籤若是設置了 download 屬性,他就會去下載這個地址。測試地址-原生 download 屬性測試ajax

下載文件,並顯示進度條

下載文件上面已經實現了,那咱們先說說如何顯示進度條。segmentfault

顯示進度條

其實瀏覽器也是有進度條的,可是我們拿不到。那咱們就來模擬一下載,而後顯示進度條。api

  1. ajax 實現下載進度條,測試地址-顯示進度條數組

    xhr = new XMLHttpRequest();
    xhr.open('get', file1.url);
    xhr.onprogress = (e)=>console.log(e)//e 就是一個 ProgressEvent 對象,其中 loaded 是已下載的, total 是總大小。
    xhr.send()
  2. fetch 實現下載進度條,測試地址-fetch顯示進度條並下載
    fetch 的實現上來講有一些功能是沒有的,好比 abort、進度等。那咱們就須要去經過一些別的手段來模擬實現。
    實現代碼以下,咱們操做成讀流,而後統計長度。
    clipboard.png

下載文件

進度條已經顯示好了,那咱們能夠下載文件了。首先咱們要分幾種狀況瀏覽器

  1. 緩存下載(一個資源若是已經下載完了,再次去訪問)
    clipboard.png
  2. 本地下載(資源已經在瀏覽器中)緩存

    1. blob url 下載 如這種地址 blob:https://www.lilnong.top/deb4c297-821c-4545-9b23-0fbdd76890c7
      clipboard.png
    2. base64 url 下載 如這種地址 data:application/octet-stream;base64,aGVsbG8gbGlub25n服務器

      blob = new Blob(['hello linong'])
        freader = new FileReader()
        freader.readAsDataURL(blob)//將 blob 讀成 dataurl
        freader.onload=e=>console.log(freader.result)// 異步的,因此須要回調裏面拿

      clipboard.png

  3. 無緩存下載(資源沒在本地,也沒有緩存)

狀況就是上面幾種,那咱們要作的其實就是統一一下流程app

  1. ajax 拉取數據(顯示進度條)
  2. 緩存了數據,而後下載緩存(由於是緩存,因此秒下)

    1. 瀏覽器緩存
      我比較推薦用這個,由於其餘的方案都有大小或者兼容上的問題。可是這個緩存須要服務器設置須要走緩存。
    2. bloburl 本地緩存下載
      這個方案在移動端異常,pc端正常,感興趣的小夥伴能夠本身實現一下,畢竟學了這麼多,得用起來才能變成本身的
    3. dataurl 本地緩存下載
      這個方案的支持會比 bloburl 好一點,可是隻適用於小文件。

實現前端下載文件並顯示進度條

咱們讓 ajax 直接返回 blob。而後構建 bloburl 用於下載。

downloadFile2 = (url)=>{
    var xhr = new XMLHttpRequest();
    xhr.open('get', url);
    xhr.responseType='blob';//這是精髓
    xhr.onprogress = onprogress2;//下載進度
    // .upload.onprogress 這個是上傳的時候的進度
    xhr.onreadystatechange = ()=>{
        if(xhr.readyState == 4 && xhr.status == 200){
            nativeDownload(URL.createObjectURL(xhr.response))
        }
    }
    xhr.send()
}

其餘類型轉換爲 blob

若是是一些封裝過的 ajax,沒辦法使用 xhr.responseType='blob' 之類的,返回回來是字符串。那咱們須要怎麼出轉換呢?

blob to *

blob 須要配合 FileReader 來讀取

  1. blob to arrayBufferreadAsArrayBuffer
    通用的、固定長度的原始二進制數據緩衝區

    var fileReader = new FileReader();
    fileReader.readAsArrayBuffer(xhr.response);//xhr.reponse 是 blob 類型
    fileReader.onload = e=>console.log(fileReader.result);

    clipboard.png

  2. blob to DataURLreadAsDataURL

    Base64 是一組類似的二進制到文本(binary-to-text)的編碼規則,使得二進制數據在解釋成 radix-64 的表現形式後可以用 ASCII 字符串的格式表示出來。Base64 這個詞出自一種 MIME 數據傳輸編碼。 --MDN

    clipboard.png

  3. blob to TextreadAsText
    以字符串表示所讀取的文件內容
    clipboard.png
  4. blob to BinaryStringreadAsBinaryString
    文件的原始二進制數據
    clipboard.png

* to blob

  1. arrayBuffer to blob
    new Blob([arrayBuffer], {type: 'image/jpeg'})
  2. base64 to blob

    (new Uint8Array(Array.from(atob(base64url.split(',')[1])).map(v=>v.charCodeAt()))).buffer
    //base64url.split(',')[1] //截取不要 data:images/jpeg;base64, 這串
    //atob //轉換成 BinaryString
    //Array.from //轉換成數組
    //map(v=>v.charCodeAt()) //轉換成對應的 ascii 碼
    //Uint8Array 轉換成 Uint8Array 而後輸出 buffer

    clipboard.png

  3. BinaryString to blob
    方案同上,由於上面的也是轉換成了BinaryString
  4. Text to blob
    ajax 默認就是 Text 類型的返回值。這個我以爲是編碼類型的轉換,好比 utf-8 to ascii,目前我還沒找到好的實現方法。

    clipboard.png

總結

以前就寫過一篇AJAX 的進階使用(Blob、ArrayBuffer、FormData、Document、JSON、Text),裏面講了這些支持的類型。
base64轉換上傳,也寫過這樣的。

前端目前須要操做的東西愈來愈多了。

在最上面那個問答裏,有個庫去實現 download 操做。實現原理能夠本身去看看。

後記

參考資料

  1. Data URLs --MDN
  2. StringView
  3. 字符編碼中ASCII、Unicode和UTF-8的區別
  4. String​.prototype​.char​CodeAt()
  5. DOMString
  6. rfc2397
相關文章
相關標籤/搜索