MST

星途 面试题库

面试题:Next.js 预加载策略在动态路由中的应用

在Next.js应用中,有一个动态路由页面 '[id].js' 用于展示不同文章详情。为了提升用户体验,你需要实现对文章详情页的预加载。描述如何结合 Next.js 的预加载策略,在用户点击文章列表链接时,提前加载对应的文章详情内容,并说明实现过程中可能遇到的性能问题及解决方法。
23.1万 热度难度
前端开发Next.js

知识考点

AI 面试

面试题答案

一键面试

结合 Next.js 预加载策略实现文章详情页预加载

  1. 使用 next/link 组件及 prefetch 属性
    • 在文章列表页面,使用 next/link 组件包裹文章链接。next/link 组件默认会在页面进入视口时预取链接对应的页面。
    • 示例代码:
import Link from 'next/link';

const ArticleList = ({ articles }) => {
  return (
    <ul>
      {articles.map((article) => (
        <li key={article.id}>
          <Link href={`/articles/${article.id}`} prefetch>
            <a>{article.title}</a>
          </Link>
        </li>
      ))}
    </ul>
  );
};

export default ArticleList;
  • 这里 prefetch 属性会在用户与链接交互(如鼠标悬停)时,提前加载链接指向的页面(即 [id].js 对应的文章详情页)。
  1. 利用 router.prefetch 手动预加载
    • 如果你想在特定的用户操作(比如点击某个按钮)时预加载文章详情页,可以使用 Next.js 的路由实例的 prefetch 方法。
    • 首先,导入 useRouter 钩子:
import { useRouter } from 'next/router';
  • 然后在组件中使用:
const SomeComponent = () => {
  const router = useRouter();
  const prefetchArticle = (articleId) => {
    router.prefetch(`/articles/${articleId}`);
  };
  return (
    <button onClick={() => prefetchArticle(someArticleId)}>
      预加载文章
    </button>
  );
};

可能遇到的性能问题及解决方法

  1. 过多预加载导致带宽浪费
    • 问题描述:如果文章列表中有大量文章,每个链接都进行预加载,会消耗大量的带宽资源,特别是在用户可能不会点击所有链接的情况下。
    • 解决方法
      • 限制预加载数量:可以通过在 next.config.js 中配置 linkPrefetchingMaxUrls 选项来限制同时预加载的链接数量。例如:
module.exports = {
  linkPrefetchingMaxUrls: 5
};
 - **条件预加载**:根据用户行为进行更智能的预加载。比如,仅在用户滚动到接近链接时才进行预加载,可以结合 `IntersectionObserver` API 实现。

2. 预加载阻塞主线程

  • 问题描述:预加载的资源可能会阻塞主线程,影响页面的交互性和渲染性能。
  • 解决方法
    • 使用 loading.js:在 Next.js 13 及更高版本中,可以创建 loading.js 文件。这个文件会在页面预加载时显示,同时允许主线程继续处理其他任务,不会阻塞用户交互。
    • 优化资源优先级:确保预加载的资源(如文章详情页的数据请求)具有适当的优先级。可以通过设置 fetch 请求的 priority 选项(在支持的浏览器中)来调整资源加载的优先级,使关键资源优先加载。例如:
fetch('your - api - url', {
  priority: 'low'
});
  1. 重复预加载
    • 问题描述:如果用户多次点击预加载过的链接,可能会导致不必要的重复预加载。
    • 解决方法
      • 缓存机制:可以在客户端实现简单的缓存机制。例如,使用 localStorage 或内存缓存(如一个简单的 JavaScript 对象)记录已经预加载过的文章 ID。在进行预加载之前,先检查缓存中是否已经存在对应的预加载结果,如果存在则不再重复预加载。
const prefetchArticle = (articleId) => {
  const cached = localStorage.getItem(`article - prefetch - ${articleId}`);
  if (!cached) {
    router.prefetch(`/articles/${articleId}`);
    localStorage.setItem(`article - prefetch - ${articleId}`, 'true');
  }
};