День за днём помощь ей с завтраком стала самым счастливым занятием дня, мои отношения с ней стали намного ближе, и мы больше не будем краснеть, когда разговариваем. Однажды в полдень она вдруг прислала сообщение, в котором говорилось, что, чтобы поблагодарить меня за то, что я помогаю ей каждый день приносить ей завтрак, она хотела пригласить меня на обед, тогда она могла только сказать, что была так счастлива, что лопнула. вон... Она повела меня на второй этаж столовой поесть острого горячего горшочка и гуляла с ней, прохожие время от времени поглядывают на нас, я не знаю, то ли это из-за ее красоты, то ли я Мне просто любопытно, что она ходит со мной одна, мне не нравится такой взгляд.
Это был первый раз, когда я ел ароматный горшок Мала, и это был также первый раз, когда я ел с ней в столовой Я чувствовал, что ароматный горшок Мала должен быть лучшим блюдом в колледже, но цена была немного высокой, так я только немного поел, ладно я должен оставить все ей.После возвращения в общежитие, мои соседи по комнате смеялись надо мной, и я наивно думал, что моя любовь была в пути, поэтому я снова приготовился признаться в ее день рождения. На этот раз я не буду трусливым...
Наконец, в день ее рождения, я рано написал ей свои пожелания и послал их после двенадцати часов, но долго не получал от нее ответа, думаю, она, должно быть, заснула. .... Я изначально планировал подарить ей торт днем, а потом попросил ее поужинать с ней. Когда я связался с ней, она уже вышла с друзьями, чтобы отпраздновать свой день рождения. Я остался один в ахуеть за торт. Такое ожидание очень мучает. , Я могу играть в Лигу Легенд только для того, чтобы ускорить время, я не могу быть доволен даже 5 убийствами....
Она сказала, что приехала, я быстро положил игру на руку, чтобы дождаться ее внизу, и я пошел к ней на некоторое время, я передал ей ее торт, сказал благословение, в ее посте Когда я пришел, я наконец набрался смелости Ты мне нравишься,можешь быть моей девушкой?
Предисловие к загрузке больших файлов
Чтобы облегчить всем чтение и понимание, я возьму в качестве примера одну загрузку большого файла, чтобы кратко описать идею.
Компонент загрузки antd перед загрузкой имеет хук, который может получить информацию о файле. Перед загрузкой файл нарезается, а затем упаковывается в один запрос и помещается в массив. При загрузке запрос массива может быть выполнен. отправить запрос на слияние после выполнения, я не использовал Promise.all для выполнения, а 2 рекурсивных выполнения.
Разрезать большие файлы сначала через срез
Ядро заключается в использовании Blob.prototype.slice
метод
createFileChunk
Принимает два параметра
dataSource: Uploaded File большой файл, размер: размер каждого осколка
//切片
createFileChunk = (dataSource, size = 5 * 1024 * 1024) => {
const fileChunkList = [];//因为只有一个文件,数组只有1项
let cur = 0;
let index = 0;//每个分片给一个索引,最后后端合并按序合并分片
let obj: IFileChunksList = {
name:dataSource.name,
progressArr: [], //记录每一个分片的上传进度
errChunkFile: [],//上传失败的文件
keys: [],//将每个分片包装成一个http请求
};
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})
};
hash
Он состоит из имени файла и серийного номера. Когда бэкэнд объединяется, его необходимо объединять по порядку.
this.createHttp
Анализ метода
Простая обработка параметров, this.request — настоящий ajax-запрос.
onProgress: отслеживайте прогресс ajax и записывайте его в режиме реального времени
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),
});
};
Создайте http-запрос для каждого сегмента
this.request
Методы обернуты обещанием и ajax
url: интерфейс загрузки сегмента. data: Параметр шардинга. onProgress: следите за ходом загрузки этого сегмента.
requestList: коллекция всех загружаемых запросов сегментов. (для возобновления с точки останова)
Вы также можете установить аутентификацию по токену в этом методе.
//创建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) => {
// 将请求成功的 xhr 从列表中删除
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,
});
});
};
Метод записи сегмента
this.createProgressHandler(data, hash)
В приведенном выше вызове метода createHttp
createProgressHandler = (item1, hash) => {
return (e: any) => {
let { fileChunkList } = this.state;
let index=hash.split("_")[1]
fileChunkList[0].progressArr[index]=e.load
this.setState({
fileChunkList,
});
};
};
Вызовите метод, чтобы начать загрузку
this.upFile(this,state.fileChunkList[0])(true)
Параметр true гарантирует, что 2 запроса будут отправлены один раз.
// 开始上传
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) {
//继续传下一个分片
loop();
} else if (init === fileArr.length && !item.errChunk.length && fileArr.length !== 1) {
//分片传完,合并分片
this.mergeChunk(item);
}
}
})
.catch((err) => {
//捕获上传失败的分片存起来
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;
};
Я не буду писать метод слияния шардов, просто вызову интерфейс.
Если есть фрагмент, который не удалось загрузить, он будет записан в fileChunkList[0].errChunkFile.Просто выполните загрузку в этот неудавшийся массив.
Возобновить с точки останова Пауза
this.state.requestList — это коллекция сегментов, запрашиваемых в настоящее время. Пауза — прервать запрос,
upFileCancel = (itemCurrent: IFileChunksList) => {
this.state.requestList.forEach((item) => {
item.xhr.abort();
});
};
Чтобы продолжить загрузку, вы можете получить те, которые были успешно загружены, а затем повторно загрузить те, которые не были загружены.
Суммировать
Я написал только общую идею реализации фронтенда, а бэкенду нужно только предоставить интерфейс для загрузки одного сегмента и интерфейс для слияния сегментов. Мой хеш использует имя файла + индекс, сspark-md5
Лучше всего генерировать хэш содержимого файла.
Загрузка одного большого файла на самом деле не сложна. Зная его общую идею, вы можете расширить загрузку в очередь из нескольких файлов, возобновить загрузку с точки останова, записать индикатор выполнения каждого файла, общий индикатор выполнения и даже индикатор выполнения каждого сегмента.При рассмотрении паузы, так как onProgress отслеживает индикатор выполнения в реальном времени, когда сегмент загружается на 80%, после отмены он становится 0, а индикатор выполнения откатывается....
Если у вас есть какие-либо вопросы о больших файлах, вы можете оставить комментарий и, наконец, поставить лайк. Передвигать кирпичи непросто
Посмотрите сюжет, чтобы узнать о принципах es6:nuggets.capable/post/702429…