如何在页面跳转时终止未完成的AWS/Cloudinary视频预加载请求?
解决跳转页面时终止未完成视频预加载请求的问题
看起来你遇到的是页面跳转后,前页面的视频下载请求仍在后台占用带宽的头疼问题——这在移动端低速网络下确实会严重影响新页面的加载体验。核心原因是浏览器不会自动终止已卸载页面中未完成的请求,而你之前尝试的abort()因为没有绑定到具体的请求实例上,所以根本起不到作用。
下面是一套可行的解决方案,核心思路是自己管理所有预加载请求的生命周期,在跳转时主动终止未完成的请求:
步骤1:维护请求控制器的全局数组
首先创建一个全局数组,用来存储每个视频预加载请求的AbortController(这是现代浏览器用来终止Fetch请求的标准API,如果需要兼容旧浏览器,可以用XHR的abort()方法,逻辑类似)。
// 全局存储所有未完成的视频预加载请求控制器 let videoPreloadControllers = [];
步骤2:重写预加载函数,手动管理请求
原来的$.cloudinary.responsive()方法会自动发起请求但不会暴露请求实例,所以我们需要自己构建Cloudinary视频URL,用Fetch发起请求并绑定控制器:
preloadVideos = function(start, end) { console.log("Video PRELOADING launched "+ start + ' to ' + end); for (var i = start; i <= end; i++) { (function () { var currentObject = VideosObject[i]; var stId = currentObject.id; var stFilename = currentObject.asset_filename; // 1. 按照Cloudinary响应式规则生成视频URL // 这里的参数要和你之前用$.cloudinary.responsive时的规则完全一致 const videoUrl = $.cloudinary.url(stFilename, { resource_type: 'video', width: 'auto', // 示例响应式参数,根据你的实际需求调整 format: 'mp4', quality: 'auto' }); // 2. 创建AbortController,用于后续终止请求 const controller = new AbortController(); const signal = controller.signal; videoPreloadControllers.push(controller); // 3. 发起预加载请求,绑定signal关联控制器 fetch(videoUrl, { signal: signal, method: 'GET', mode: 'no-cors' // 如果跨域访问Cloudinary资源可能需要这个配置 }).then(() => { // 请求完成后,从数组中移除控制器 const index = videoPreloadControllers.indexOf(controller); if (index !== -1) videoPreloadControllers.splice(index, 1); // 标记视频已预加载完成 const $videoEl = $('#videoAsset-' + stId); $videoEl.attr('data-response-status', 1); $videoEl.attr('src', videoUrl); // 将预加载好的URL设置给视频元素 }).catch(error => { // 主动终止的请求不需要抛出错误提示 if (error.name !== 'AbortError') { console.error(`预加载视频${stId}失败:`, error); } // 移除控制器 const index = videoPreloadControllers.indexOf(controller); if (index !== -1) videoPreloadControllers.splice(index, 1); }); })(); } }
步骤3:修改跳转按钮的点击事件
在跳转前遍历控制器数组,终止所有未完成的请求:
<a href="<%= deal_page_path(@next_deal) %>" title="move to next page" class="action-btn" onclick="handlePageJump(event);">Next page</a>
对应的处理函数:
function handlePageJump(event) { // 终止所有未完成的视频预加载请求 videoPreloadControllers.forEach(controller => controller.abort()); // 清空控制器数组 videoPreloadControllers = []; // 允许默认的页面跳转行为(如果需要确保请求完全终止后再跳转,可以加个50ms左右的微小延迟) // setTimeout(() => window.location.href = event.target.href, 50); }
为什么之前的方法无效?
你之前尝试的abort()没有作用,是因为它没有绑定到具体的请求实例上——$.cloudinary.responsive()内部创建的HTTP请求是由Cloudinary的JS库自行管理的,没有暴露给你的代码,所以你无法直接终止这些请求。通过手动发起请求并管理AbortController,你才能拿到每个请求的控制权,在需要时主动终止。
额外注意事项
- 确保Cloudinary URL的生成参数和你之前使用
$.cloudinary.responsive()时的一致,否则预加载的视频资源可能不匹配。 - 如果需要兼容不支持
AbortController的旧浏览器,可以用XMLHttpRequest替代Fetch,调用xhr.abort()来终止请求,逻辑是一样的。 - 可以在
beforeunload事件中也加入终止请求的逻辑,覆盖用户直接刷新或关闭页面的场景。
内容的提问来源于stack exchange,提问作者Mathieu
相关产品推荐
相关产品推荐

