As the days went by, helping her bring breakfast became the happiest thing of the day, and I became much closer to her and no longer blushed when we talked. One day at noon, she suddenly sent a message to say that she would invite me to lunch in order to thank me for bringing her breakfast every day. At that time, I could only say that I was so happy that I burst into tears. She took me to the second floor of the canteen to eat spicy spicy pot. Passers-by would glance at us from time to time when we were walking together. I didn’t know whether it was because of her beauty or curiosity that she was walking with me alone. It was my first time to eat spicy balsamic pot, also is the first time and her in the cafeteria, we feel spicy pot should be the most good things to eat, the university is the prices are a little bit, I only eat a little bit, all good things will be left to her, return to dormitory, roommates are teasing me, I also naive to think my love is on its way, so I’m ready to do on her birthday. I won’t lose it this time… Finally arrived at her birthday that day, I early wrote good to her blessing, twelve o ‘clock over to send her, can wait for a long time did not wait for her reply, I think she should be asleep….. Originally planned to give her the cake in the afternoon, and then about her to have a dinner, contact her, she had gone out with friends to celebrate the birthday, alone left me in a daze to the cake, this kind of waiting is very suffering things, can only play the league of heroes to let the time pass quickly, 5 kill I also can not lift the slightest bit of happiness…. She said she was coming, I hurriedly put down the game to her downstairs and so on, and so on for a long time to see her, I put the cake carefully handed to her, said a pile of blessing, when she was going upstairs, I finally mustered the courage to say, I like you, can you be my girlfriend?

Preface to uploading large files

In order to facilitate your reading and understanding, I will take a single large file upload as an example to briefly describe the idea. The upload component of ANTD has a hook before uploading, in which you can get file information, slice the file before uploading, package it into one request after another, and put it into an array. When uploading, you can execute the array request, and send a merge request after execution. I did not use Promise. It’s a two-by-two recursive execution.

Slice large files first

The core is to use the blob.prototype. slice method

CreateFileChunk Accepts two parameters dataSource: large File uploaded; size: size of each fragment

  / / section
     createFileChunk = (dataSource, size = 5 * 1024 * 1024) = > {
        const fileChunkList = [];// Because there is only one file, the array has only 1 item
        let cur = 0;
        let index = 0;// Each shard is given an index, and finally the shard is merged in order
        let obj: IFileChunksList = {
            name:dataSource.name,
            progressArr: [].// Record the upload progress of each shard
            errChunkFile: [].// Failed to upload the file
            keys: [].// Wrap each shard as an HTTP request
        };

        let arr = [];
        while (cur < dataSource.size) {
            arr.push(this.createHttp({ hash:dataSource.name+'_'+index, file: dataSource.slice(cur, cur + size)}));
            index += 1;
            cur += size;
        }
        obj.keys = arr;
        fileChunkList.push(obj);
        this.setState({fileChunkList})
    };
Copy the code

Hash consists of a file name and sequence number. The hash must be merged in sequence when the backend is merged.

The this.createHttp method simply does the parameter processing, and this. Request is the real Ajax request onProgress: listens for ajax progress and records it in real time

   createHttp = (data) = > {
        const { hash, file } = data;
        const formData = new FormData();
        formData.append('chunk', file);
        formData.append('hash', hash);
        return () = >
            this.request({
                url: this.props.action,
                data: formData,
                onProgress: this.createProgressHandler(data, hash),
            });
    };
Copy the code
Create an HTTP request for each shard

The this.request method wraps the URL with promise and Ajax: the Shard upload interface. Data: fragment parameter. OnProgress: monitors the upload progress of this fragment. RequestList: A collection of fragmented requests that are being uploaded. You can also set token authentication in this method

   / / create ajax
    request = ({
        url, 
        method = 'post',
        data,  
        onProgress = (e: any) => e,
        requestList = this.state.requestList,
    }: IAjax) = > {
        return new Promise((resolve, reject) = > {
            const xhr = new XMLHttpRequest();
            xhr.upload.onprogress = onProgress;
            xhr.open(method, url, true);
            xhr.setRequestHeader('Authorization'.this.props.token);
            xhr.send(data);
            xhr.onload = (e: any) = > {
                // Delete the XHR successfully requested from the list
                const { requestList } = this.state;
                if (requestList) {
                    const xhrIndex = requestList.findIndex((item) = > item.xhr === xhr);
                    requestList.splice(xhrIndex, 1);
                    this.setState({ requestList });
                }
                resolve({
                    data: e.target.response,
                });
            };
            xhr.onerror = (e) = > {
                reject(e);
                // throw new Error('fail');
            };
            requestList.push({ xhr, hash:data.get('hash')});

            this.setState({
                requestList,
            });
        });
    };
Copy the code
Method of recording sharding progress

Enclosing createProgressHandler (data, hash) above createHttp method call

  createProgressHandler = (item1, hash) = > {
        return (e: any) = > {
            let { fileChunkList } = this.state;
            let index=hash.split("_") [1]
            fileChunkList[0].progressArr[index]=e.load
            this.setState({
                fileChunkList,
            });
        };
    };
Copy the code
Call the method to start uploading

This.upfile (this, state.filecHunkList [0])(true) The true argument guarantees two requests

 // Start uploading
    upFile = ( item) = > {
        let fileArr=item.keys
        let init = 0;
        let loopFun = (initValue) = > {
            fileArr[initValue]()
                .then((res) = > {
                    if (JSON.parse(res.data).statusCode === 200) {
                        init++;
                        if (init < fileArr.length) {
                         // Continue to pass the next shard
                            loop();
                        } else if(init === fileArr.length && ! item.errChunk.length && fileArr.length ! = =1) {
                        // Merge the fragments
                            this.mergeChunk(item);
                        }
                    } 
                })
                .catch((err) = > {
                // Capture the fragments that failed to upload and save them
                    let arrChunk = item.errChunkFile.concat(fileArr[initValue]);
                    init++;
                    item.errChunkFile = arrChunk;
                    this.setState({
                        fileChunkList: [...item],
                    });
                    if(init < fileArr.length) { loop(); }}); };let loop = (initFlag) = > {
            loopFun(init);
            if(initFlag) { loopFun(++init); }};return loop;
    };
Copy the code

I’m not going to write the shard merge method, just call an interface. If a fragment fails to upload, it is recorded in fileChunkList[0]. ErrChunkFile. Just do an upload on the failed array.

The breakpoint continuation is suspended

This.state. requestList is the collection of fragments currently being requested. Pause is when the request is abort,

upFileCancel = (itemCurrent: IFileChunksList) = > {
        this.state.requestList.forEach((item) = > {
                item.xhr.abort();
        });
    };
Copy the code

Continuation, you can get the successful upload, and then not uploaded to upload again.

conclusion

I only wrote the rough implementation idea of the front end, the back end only needs to provide a single shard upload interface, shard merge interface. I use file name + index for hash, and spark-MD5 is the most appropriate way to generate a hash for the file content.

A single large file upload feeling actually not complex, know the general idea to extend the file upload queue, breakpoint continuingly, recording the progress bar of each file, the total progress bar each subdivision of the progress bar, even consider suspended, because onProgress is real-time monitoring of the progress bar, upload when divided by eighty percent, becomes zero after cancel, Progress bar rollback….

If you have any questions about the big file, please comment and give a “like”. Brick is not easy to carry

See the story to learn the es6 principle: juejin.cn/post/702429…