• 彻底理解responseType中blob和arrayBuffer


    一般的xhr请求

     let url = window.URL || window.webkitURL;

    let xhr = new XMLHttpRequest();

    xhr.open(method, url, [,async=true,]);

    xhr.ontimeout = ()=>{};

    xhr.onreadystatechange ()=>{

    if(xhr.readystate === 4) {

    if(xhr.status =200) {

    let res = xhr.responseText;

    let blob = new Blob([res], {type: 'video/mpeg4'});

    videoEle.src = url.createObjectURL(blob);

    };

    }

    };

     上面代码处理一般的xhr请求足够满足,即返回类型为DOMString的,但是处理视频下载并且存储后播放就会有问题,上面代码处理异步视频下载有两个bug,如果你都知道,就不需要往下看了^_^

    再次认识responseType

    responseType值的类型可为如下

    数据类型
    ’ ‘DOMString (这个是默认类型)
    arraybufferArrayBuffer对象
    blobBlob对象
    documentDocument对象
    jsonJavaScript object, parsed from a JSON string returned by the server
    textDOMString

    video后台为设置的content-type为application/octet-stream,表示二进制流。。当时就被这货坑了一下,以为返回的数据能够够Blob构造函数接收,并正确显示。

     

    Blob对象

    Blob也是比较有意思,mdn上的解释是Blob对象表示不可变的类似文件对象的原始数据。Blob表示不一定是JavaScript原生形式的数据。

    ^_^其实就是英文Binary large Object,mysql有此类型数据结构

    let blog = new Blob(arrya, options);
    • 1

    Blob() 构造函数返回一个新的 Blob 对象。

    • array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings会被编码为UTF-8。

    • options 是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性:

      type,默认值为 “”,它代表了将会被放入到blob中的数组内容的MIME类型。


    ArrayBuffer涉及面比较广,我的理解是ArrayBuffer代表内存之中的一段二进制数据,一旦生成不能再改。可以通过视图(TypedArray和DataView)进行操作。

    TypedArray数组只是一层视图,本身不储存数据,它的数据都储存在底层的ArrayBuffer对象之中, 所以通过同一个arraybuffer生成的TypedArray共享内存数据。

    nodejs中的buffer是对Uint8Array的实现。详细可参考另外一篇我写的文章


    正确的video流打开方式

    还有一点xhr.responseText的类型为DOMString,只有当responseType为DOMString时才有正确数据,其他类型获取响应实体用xhr.response。因为一般我们都是获取json字符串,此处也需要注意下。 
    so正确的代码如下:

    let url = window.URL || window.webkitURL;     let xhr = new XMLHttpRequest();     xhr.open(method, url, [,async=true,]);     xhr.responseType = 'blob' ; //arraybuffer也可以     xhr.ontimeout = ()=>{};     xhr.onreadystatechange=()=>{       if(xhr.readystate === 4) {         if(xhr.status =200) {             let res = xhr.response;  //不是responseText。           /*           *最近看别人的代码,发现可以这么写           * let res = 'response' in xhr ? xhr.response : xhr.responseText           * 厉害!!!           */           let blob = new Blob([res], {type: 'video/mpeg4'});           ....           ....           videoEle.src = url.createObjectURL(blob);           //Videos on Android do not play when the src is set as a blob via create URL, 在移动端有兼容问题         };       }     };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    后面的内容与本文无关,纯作记录。

    后续

    项目中的video都存储在移动设备中,如果都放在blob中,会造成内存的大量占用,因是cordova的webapp形式,故采用插件cordova-plugin-file, 
    相关写文件代码如下

    function writeSystemFile(videoBlob, isAppend) {     let self = this;     window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {       //console.log('openFsObj', fs);       //console.log('open file name: ', fs.name);       fs.root.getFile(self._storeVideoName, { create: true, exclusive: false },function (fileEntry) {         // var dataObj = new Blob([videoData], { type: 'text/plain' });         self.writeFile(fileEntry, videoBlob, isAppend);       }, function(e) {         console.log('onErrorCreateFile, error:', e);       });     }, function(e) {       console.log('onErrorLoadFs, error:', e);     });   }    function writeFile(fileEntry, dataObj, isAppend) {     // let self = this;     fileEntry.createWriter(function (fileWriter) {       fileWriter.onwriteend = function() {         console.log('Successful file write...');         //console.log('fileWriterEnd.length:', fileWriter.length);       };       fileWriter.onerror = function (e) {         console.log('Failed file write: ' + e.toString());       };       if(isAppend) { //表示是否追加文件         try {           console.log('fileWriter.length:', fileWriter.length);           fileWriter.seek(fileWriter.length);         } catch(e) {           console.log('file doesn`t exist:', e.toString());         }       }       //console.log('fileWriterStart.length:', fileWriter.length);       fileWriter.write(dataObj);      });   }
    • 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
    • 39

    读文件代码

    function readSystemFile() {     let self = this;     console.log('readSystemFile self._storeVideoName:', self._storeVideoName);     window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {       fs.root.getFile(self._storeVideoName, { create: true, exclusive: false },function (fileEntry) {         self.readFile(fileEntry);       }, self.onErrorCreateFile);     }, function (error) {       console.log('onErrorLoadFs, error:', error);     });   }   function readFile(fileEntry) {     let self = this;     fileEntry.file(function (file) {       var reader = new FileReader();       reader.onloadend = function() {         if(this.result === null) {           console.log('readFile unexpected this.result == null');           return;         }         console.log(typeof this.result);         console.log('Successful file read length: ', this.result.length);         // var blob = new Blob([new Uint8Array(this.result)], { type: "video/mpeg4" });         console.log('Successful file read: ', this.result);       };       // reader.readAsText(file);       reader.readAsArrayBuffer(file);       // reader.readAsBinaryString(file);     }, self.onErrorReadFile);   }  onErrorReadFile() {     console.log('Failed file read: ');   }
    • 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

    因安卓和ios下文件的存储路径不一样,故需要做一个判断,文件的存储目录

    function getDirectory() {     let isIOS =/(iPad|iPhone|iPod)/g.test(navigator.userAgent);     if(isIOS) {       return cordova.file.documentsDirectory;     }else {       return cordova.file.dataDirectory + 'files/';     } }
  • 相关阅读:
    Using CocoaPods
    IMPROVING IOS UNIT TESTS WITH OCMOCK
    梦想不为斗室所缚
    【转】class 'org.springframework.orm.hibernate3.LocalSessionFactoryBean' not found解决办法
    我们去工作是为了什么?——迈锡尼
    查看已保存的wifi密码
    点球成金
    研究生开口月薪一万 企业暗示“靠边站”
    程序员技术练级攻略
    Emacs是一种信仰!世界最强编辑器介绍 (转自王珢)
  • 原文地址:https://www.cnblogs.com/hsdying/p/9660365.html
Copyright © 2020-2023  润新知