防抖节流/大文件上传

36 阅读2分钟

防抖和节流

解释

  • 防抖(Debounce):确保在指定时间内函数只执行一次,常用于输入框的搜素建议
  • 节流(Throttle):确保在指定时间间隔内函数执行一次,常用于窗口的resize/scroll事件

防抖

function debounce(func, wait) {
    let timeout;
    return function(...args) {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            fun.apply(this, args);
        }, wait)
    }
}

//使用防抖函数
const debouncedFetchData = debounce((query)=> {
    fetchData(`/api/search?q=${query}`).then(data => {
        console.log(data)
    })
}, 300);
//输入框事件监听
document.getElementById('search-input').addEventListener('input', (event) => {
    debouncedFetchData(event.target.value);
})

节流

function throttle(func, limit) {
    let inThrottle;
    return function(...args) {
        if(!inThrottle) {
        func.apply(this, args);
        inThrottle = true;
        setTimeout(() => inThrottle = false, limit);
        }
    }
}
//使用节流函数
const throttleFetchData = throttle(() => {
    fetchData('/api/updates').then(data => {
        console.log(data);
    })
},1000)
//窗口滚动事件监听
window.addEventListener('scroll', throttledFetchData);

如何解决页面请求接口大规模并发问题

1.大数据请求场景下,我们选用了请求队列,封装请求队列

2.防抖节流,用户交互层面上去解决减少请求的处理

3.分页、滚动加载,可视区绘制

大文件上传

背景

涉及到用户自定模型(1G以上)

经常遇到一些问题
  • 网络断开之后,之前传的没了
  • 传着传着,网络波动了,结果啥都没了
  • 关机了,想接着传,做不到
专业术语
  • 断电续传
  • 断开重连重传
  • 切片上传
方案
  • 前端切片 chunk 1024M(1048576K),500K,const size = 1048576/500
  • 将切片传递给后端,切的片要取名:hash,index
  • 后端组合切片
给面试官加料
  • 前端切片:主进程做卡顿,web-worker 多线程切片,处理完后交给主进程发送
  • 切完后,将blob,存错到IndexedDB,下次用户进来之后,嗅探一下是否存在未完成上传的切片,有就继续上传
  • websocket,实时通知,和请求序列的控制wss
  • 整体说一说主导这个大文件上传器整体设计
  • 组件设计
  • props、事件、状态
  • 拖拽上传、多文件选择
  • 通用化不同文件的上传,上传统一协议
落地
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chunk File Upload</title>
</head>
<body>
    <input type="file" id="fileInput">
    <button onclick="uploadFile()">Upload</button>
</body>
<script>
    const CHUNK_SIZE = 5 * 1024 * 1024; //每块大小为5MB
    function uploadFile() {
        const file = document.getElementById('fileInput').files[0];
        if(!file) {
            alert('Please select a files');
            return;
        }
        const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
        let currentChunk = 0;
        function uploadChunk() {
            if(currentChunk >= totalChunks) {
                console.log('Upload complete');
                return;
            }
            const start = currentChunk * CHUNK_SIZE;
            const end = Math.min(start + CHUNK_SIZE, file.size);
            const chunk = file.slice(start, end);
            const formData = new FormData();
            formData.append('file', chunk);
            formData.append('chunkNumber', currentChunk + 1);
            formData.append('totalChunks', totalChunks);
            fetch('/upload', {
                method: 'POST',
                body: formData
            }).then(response => {
                if(response.ok) {
                    currentChunk ++;
                    uploadChunk(); //递归调用上传下一块
                } else {
                    console.error('Chunk upload failed');
                }
            }).catch(error => {
                console.error('Upload error', error)
            })
        }
        uploadChunk();
    }
</script>
</html>