切片上传

来源:互联网 发布:日本人的气质 知乎 编辑:程序博客网 时间:2024/06/05 04:21
<script>
initUpload();


//初始化上传
function initUpload() {
    var chunk = 100 * 1024;   //每片大小
    var input = document.getElementById("file");    //input file,获取上传文件
    input.onchange = function (e) {//文件筐选中文件触发事件
        var file = this.files[0];//得到文件对象
        var query = {};//ajax的数据
        var chunks = [];//存放切片文件
        if (!!file) {//undifined和null时,用一个感叹号返回的都是true,用两个感叹号返回的就是false,如果明确设置了变量的值(非null/undifined/0/""等值),结果就会根据变量的实际值来返回,如果没有设置,结果就会返回false。
            var start = 0;//切片开始位置
            //文件分片
            for (var i = 0; i < Math.ceil(file.size / chunk); i++) {//循环,结束条件是文件大小/每片大小向上取整
                var end = start + chunk;//结束位置等于起始位置加每片大小
                chunks[i] = file.slice(start , end);//文件使用slice方法确定起止位置切片数据放入数组
                start = end;//开始位置重定义为上次结束位置,进入下次循环
            }
            
            // 采用post方法上传文件
            // url query上拼接以下参数,用于记录上传偏移
            // post body中存放本次要上传的二进制数据
            query = {//数据
                fileSize: file.size,//文件大小
                dataSize: chunk,//每片大小
                nextOffset: 0//下次偏移
            }


            upload(chunks, query, successPerUpload);//执行方法,参数1是文件切片数组,参数二是query数组,参数三是每片上传完后重新调用upload方法,所有切片上传完后,结束调用类似递归
        }
    }
}


// 执行上传
function upload(chunks, query, cb) {//上传方法:参数1是文件切片数组,参数二是query数组,参数三是每片上传完后重新调用upload方法,所有切片上传完后,结束调用类似递归
    var queryStr = Object.getOwnPropertyNames(query).map(key => {
        return key + "=" + query[key];
    }).join("&");//组合成拼接字符串
    var xhr = new XMLHttpRequest();//ajax请求
    xhr.open("POST", "http://xxxx/opload?" + queryStr);//请求地址,加拼接参数
    xhr.overrideMimeType("application/octet-stream");//二进制文件格式
    
    //获取post body中二进制数据
    var index = Math.floor(query.nextOffset / query.dataSize);//位移/大小,向下取整
    getFileBinary(chunks[index], function (binary) {//调用方法获取二进制数据,参数1是当前片数,参数二回调函数
//在调用函数后,得到函数获取的result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。在发送二进制数据
        if (xhr.sendAsBinary) {//如果是二进制,已经快要废除的方法
            xhr.sendAsBinary(binary);//就按二进制发送
        } else {
            xhr.send(binary);//直接发送
        }


    });


    xhr.onreadystatechange = function (e) {//ajax回调
        if (xhr.readyState === 4) {//ajax呼叫成功
            if (xhr.status === 200) {//ajax返回成功
                var resp = JSON.parse(xhr.responseText);//返回值解析成对象
                // 接口返回nextoffset
                // resp = {
                //     isFinish:false,
                //     offset:100*1024
                // }
                if (typeof cb === "function") {
                    cb.call(this, resp, chunks, query)
                }
            }
        }
    }
}


// 每片上传成功后执行
function successPerUpload(resp, chunks, query) {//1,ajax返回对象,2数据本身,3是切片参数
    if (resp.isFinish === true) {
        alert("上传成功");
    } else {
        //未上传完毕
        query.offset = resp.offset;
        upload(chunks, query, successPerUpload);
    }
}


// 获取文件二进制数据
function getFileBinary(file, cb) {//第一个是文件,第二个是方法
    var reader = new FileReader();//FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
//FileReader 提供的 readAsArrayBuffer() 方法会开始读取制定的 Blob 或 File 对象。
//当读取操作完成的时候,readyState 变成已完成(DONE),并触发 loadend 事件,同时 result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。
    reader.readAsArrayBuffer(file);
    reader.onload = function (e) {//读取完文件触发onload事件
        if (typeof cb === "function") {//typeof强制转换cb参数得到类型,如果cb是个方法
            cb.call(this, this.result);//调用方法的call回调函数,传回reader本身与reader读取完文件的result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。也就是读取的数据
        }
    }
}


</script>
<!--总结:
初始化上传执行initUpload()
规定切片大小,得到文件数据,把文件分割成片存入数组,
定义参数
调用upload()上传
Upload方法1个参数是数据,2个参数是参数配置,3个参数是递归方法,切片没完成的时候继续调用
upload里面又有getFileBinary()获取二进制数据,每次发送二进制数据
successPerUpload()方法内在调用upload方法,形成循环链,到切片上传完成结束循环连
-->
原创粉丝点击