You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断所有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;
    }
}

关键修改说明

  1. 模型加载与事件绑定解耦:

    • 只有在所有模型加载完成后,才绑定视频的播放/暂停事件,从根源上保证启动摄像头时模型已就绪
    • 用modelsLoaded变量做状态标记,双重保障逻辑可靠性
  2. 摄像头操作优化:

    • 启动摄像头时增加判断,避免重复请求媒体流
    • 关闭摄像头时不仅清空srcObject,还停止所有媒体轨道,确保摄像头真正释放
  3. HTML标签修正:

    • 原代码中错误地用script标签引入CSS文件,改为正确的link标签,避免样式加载失败

内容的提问来源于stack exchange,提问作者Samir Paruthi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 17:05:18