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

Next.js嵌入Wistia视频致Lighthouse移动端TTI升高问题咨询

Next.js 项目零TTI损耗加载Wistia视频方案

问题背景

现有基于MUI、NextAuth.js技术栈的Next.js项目,需求为加载Wistia视频的同时,不影响Lighthouse移动端Time-to-Interactive(可交互时间,简称TTI)指标。
直接在组件中通过Next.js的Script组件写入如下嵌入代码时,TTI会出现大幅上涨:

<div>
  <Script src={`https://fast.wistia.com/embed/medias/${wistiaId}.jsonp`} strategy="beforeInteractive"/>
  <Script src={"https://fast.wistia.com/assets/external/E-v1.js"} defer />
  <Box
     className={`wistia_embed wistia_async_${wistiaId}`}
     sx={{ position: "absolute", top: 0, left: 0, right: 0 }}
  />
</div>

经Lighthouse检测,未做优化的嵌入逻辑会使TTI增加约3.2秒,检测结果如下:
未优化版本Lighthouse检测截图
此前尝试的优化方案为监听scroll、touch等用户输入事件,事件触发后再加载Wistia相关脚本,该方案确实可将TTI影响降到极低水平,检测结果如下:
优化版本Lighthouse检测截图
但该方案存在明显缺陷:必须提前渲染完成视频播放器界面,无法展示加载状态提示。

核心问题

  1. 是否存在无需等待用户输入即可完成Wistia视频嵌入,且完全不对TTI指标造成负面影响的方案?
  2. Next.js中是否可以感知页面达到可交互状态的时机,从而无需等待用户输入即可延迟加载视频资源?

方案实现

页面可交互时机感知逻辑

Next.js本身未直接暴露页面达到TTI标准的生命周期钩子,但可通过浏览器原生API实现感知,无需绑定用户输入事件:

  • 禁止使用beforeInteractive、afterInteractive两个Script策略加载Wistia资源:前者会阻塞首屏渲染,后者会在页面hydration阶段立即执行脚本,产生的长任务会直接拖慢TTI。
  • 监听浏览器原生load事件,事件触发后通过requestIdleCallback将脚本加载逻辑注册到浏览器空闲时段执行。该时间点所有首屏关键资源已加载完成,hydration执行完毕,此时加载非关键的视频脚本不会阻塞主线程,完全不会影响TTI统计。
  • 逻辑可直接封装在客户端useEffect中执行,useEffect本身仅会在客户端hydration完成后触发,叠加空闲判断即可保证加载时机安全。

无用户交互零TTI损耗嵌入方案

基于上述时机判断逻辑即可实现需求,无需等待任何用户操作,同时支持自定义加载提示,完整实现代码如下:

import { useState, useEffect } from 'react'
import Script from 'next/script'
import Box from '@mui/material/Box'

const WistiaVideoEmbed = ({ wistiaId }) => {
  const [loadVideoAssets, setLoadVideoAssets] = useState(false)

  useEffect(() => {
    const scheduleLoad = () => {
      if ('requestIdleCallback' in window) {
        // 空闲时加载,最长等待2秒兜底
        requestIdleCallback(() => setLoadVideoAssets(true), { timeout: 2000 })
      } else {
        // 低版本浏览器兜底延迟
        setTimeout(() => setLoadVideoAssets(true), 1500)
      }
    }

    if (document.readyState === 'complete') {
      scheduleLoad()
    } else {
      window.addEventListener('load', scheduleLoad, { once: true })
    }

    return () => window.removeEventListener('load', scheduleLoad)
  }, [])

  return (
    <div>
      {loadVideoAssets && (
        <>
          <Script 
            src={`https://fast.wistia.com/embed/medias/${wistiaId}.jsonp`}
            fetchPriority="low"
          />
          <Script 
            src="https://fast.wistia.com/assets/external/E-v1.js"
            fetchPriority="low"
          />
        </>
      )}
      <Box
        className={loadVideoAssets ? `wistia_embed wistia_async_${wistiaId}` : ''}
        sx={{ position: "absolute", top: 0, left: 0, right: 0 }}
      >
        {/* 可自由替换为占位图、自定义Loading组件 */}
        {!loadVideoAssets && <div className="video-placeholder">视频加载中...</div>}
      </Box>
    </div>
  )
}

export default WistiaVideoEmbed

额外优化建议

  • 若视频不在首屏视口范围内,可叠加Intersection Observer逻辑,等视频滚动到距视口200-300px范围时再触发加载,性能收益更高。
  • Wistia脚本默认会预加载部分视频分片资源,可在初始化时配置Wistia播放器的预加载策略为preload="none",进一步降低非必要资源加载对主线程的占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:06:22