如何判断所有Promise已完成?实现视频联动摄像头且模型仅加载一次
解决方案
核心思路
- 模型仅在页面加载时通过
Promise.all加载一次,页面刷新才会重新触发加载 - 等待所有模型加载完成后,再绑定视频的播放/暂停事件,确保启动摄像头前模型已就绪
- 播放时启动摄像头,暂停时彻底关闭摄像头,重复播放直接复用已加载的模型,无需重新加载
修改后的代码
Index.php(修正标签错误,其余保持原结构)
<html> <head> <title>Video detecting and emotion storing in database</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="style.css"> <script defer type="text/javascript" src="script/face-api.min.js"></script> <script defer type="text/javascript" src="script/script.js"></script> <style> #livecam{ height: 400px; width: 600px; float: right; } </style> </head> <body> <div class="container"> <video id="myvideo" src="laravel.mp4" controls height="400" width="600" > </video> <video id="livecam" autoplay muted height="400" width="600" ></video> </div> </body> </html>
script.js(核心逻辑修改)
const video = document.getElementById('myvideo'); const liveview = document.getElementById('livecam'); // 标记模型加载状态 let modelsLoaded = false; // 一次性加载所有模型,页面刷新才会重新执行 Promise.all([ faceapi.nets.tinyFaceDetector.loadFromUri('/models'), faceapi.nets.faceLandmark68Net.loadFromUri('/models'), faceapi.nets.faceRecognitionNet.loadFromUri('/models'), faceapi.nets.faceExpressionNet.loadFromUri('/models') ]).then(() => { modelsLoaded = true; console.log('所有模型加载完成'); // 模型就绪后再绑定视频事件 bindVideoEvents(); }).catch(err => { console.error('模型加载失败:', err); }); function bindVideoEvents() { video.onplaying = function() { if (modelsLoaded) { enablewebcam(); console.log("Video is playing"); } }; video.onpause = function() { disablecam(); }; } function enablewebcam() { // 避免重复请求摄像头流 if (liveview.srcObject) return; navigator.mediaDevices.getUserMedia({ video: {width: 600, height: 400}, audio: false }).then((stream) => { liveview.srcObject = stream; }).catch(err => { console.error('摄像头启动失败:', err); }); } function disablecam() { const stream = liveview.srcObject; if (stream) { // 停止所有媒体轨道,彻底关闭摄像头 const tracks = stream.getTracks(); tracks.forEach(track => track.stop()); liveview.srcObject = null; } }
关键修改说明
模型加载与事件绑定解耦:
- 只有在所有模型加载完成后,才绑定视频的播放/暂停事件,从根源上保证启动摄像头时模型已就绪
- 用
modelsLoaded变量做状态标记,双重保障逻辑可靠性
摄像头操作优化:
- 启动摄像头时增加判断,避免重复请求媒体流
- 关闭摄像头时不仅清空
srcObject,还停止所有媒体轨道,确保摄像头真正释放
HTML标签修正:
- 原代码中错误地用
script标签引入CSS文件,改为正确的link标签,避免样式加载失败
- 原代码中错误地用
内容的提问来源于stack exchange,提问作者Samir Paruthi
相关产品推荐
相关产品推荐

