移动端Chrome切换前后摄像头时HTML5 video play请求永久pending问题
问题根因
你遇到的Chrome独有的play() Promise pending问题,核心来自stopWebCam方法的异步执行逻辑:你在方法内部用了setTimeout(() => {}, 0)将旧流停止、srcObject置空的操作放入了异步宏队列,调用stopWebCam()后会立刻执行后续的getUserMedia申请新流、赋值srcObject、调用play的逻辑,此时旧流的清理操作还没执行,Chrome对video元素的媒体流状态切换校验比其他浏览器严格,新旧流的状态冲突就会导致play操作卡住,Promise长期处于pending状态。
修复方案
- 第一步:修改
stopWebCam方法,去掉不必要的异步延迟,改成同步执行逻辑;如果必须保留异步逻辑,可封装为Promise确保清理完成后再返回:
// 同步版本,直接执行清理逻辑 let stopWebCam = function (pictureType) { let videoStream = document.getElementById('captureCandidateId'); const stream = videoStream.srcObject; if (stream && stream.getTracks) { const tracks = stream.getTracks(); tracks.forEach(function(track) { track.stop(); }); } videoStream.srcObject = null; } // 保留异步的Promise版本 let stopWebCam = async function (pictureType) { return new Promise((resolve) => { setTimeout(()=>{ let videoStream = document.getElementById('captureCandidateId'); const stream = videoStream.srcObject; if (stream && stream.getTracks) { const tracks = stream.getTracks(); tracks.forEach(function(track) { track.stop(); }); } videoStream.srcObject = null; resolve(); }, 0) }) }
- 第二步:调整主逻辑,确保旧流完全清理后再申请新流、触发播放。如果使用Promise版的
stopWebCam,需要加await等待执行完成:
try { // 同步版本直接调用即可,使用Promise版本需要改为 await stopWebCam() stopWebCam(); // 切换摄像头建议明确指定facingMode,避免getUserMedia返回错误的摄像头流 // 前置示例:{video: {facingMode: "user"}},后置示例:{video: {facingMode: "environment"}} stream = await navigator.mediaDevices.getUserMedia({video: true}); let videoStream = document.getElementById('captureCandidateId'); videoStream.srcObject = stream; var playPromise = videoStream.play(); if (playPromise !== undefined) { playPromise.then(_ => { // 自动播放已启动,展示播放态UI }) .catch(error => { // 自动播放被阻止,展示暂停态UI }); } } catch(err) { console.log(err.name + ": " + err.message); }
内容的提问来源于stack exchange,提问作者shubham kapoor
相关产品推荐
相关产品推荐

