MST

星途 面试题库

面试题:Vue生命周期钩子异步数据加载与SSR的融合实践

在使用Vue进行服务端渲染(SSR)的项目中,异步数据加载在生命周期钩子中的实现与传统客户端渲染有很大不同。请详细描述在SSR场景下,如何在Vue生命周期钩子中进行异步数据加载,包括如何处理服务端和客户端数据的一致性问题,以及如何优化SSR场景下异步数据加载带来的性能开销,给出具体的代码示例和优化策略。
28.5万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

SSR场景下异步数据加载在Vue生命周期钩子中的实现

在SSR场景下,通常会在createdbeforeMount钩子中进行异步数据加载。由于服务端渲染没有真实的DOM,所以mounted钩子在服务端不会被调用。

示例代码

假设我们有一个简单的Vue组件,需要从API获取数据:

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ content }}</p>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      title: '',
      content: ''
    };
  },
  async created() {
    try {
      const response = await axios.get('/api/article');
      this.title = response.data.title;
      this.content = response.data.content;
    } catch (error) {
      console.error('Error fetching data:', error);
    }
  }
};
</script>

处理服务端和客户端数据一致性问题

  1. 预取数据:在服务端渲染时,我们可以在渲染组件之前,提前获取异步数据,并将数据注入到组件的状态中。这样,客户端渲染时可以直接使用服务端已经获取到的数据,避免重复请求。
  2. 使用window.INITIAL_STATE:在服务端渲染时,将获取到的数据挂载到window.__INITIAL_STATE__对象上,然后在客户端的入口文件中,将该对象的数据合并到Vuex状态树或组件的data中。

服务端示例代码

// server.js
import Vue from 'vue';
import App from './App.vue';
import axios from 'axios';

export default async context => {
  const app = new Vue({
    render: h => h(App)
  });

  try {
    const response = await axios.get('/api/article');
    app.$data.title = response.data.title;
    app.$data.content = response.data.content;
  } catch (error) {
    console.error('Error fetching data on server:', error);
  }

  context.state = app.$data;
  return app;
};

客户端示例代码

// main.js
import Vue from 'vue';
import App from './App.vue';

if (window.__INITIAL_STATE__) {
  // 这里假设App组件有data可以直接合并,如果使用Vuex,需要按Vuex的方式合并
  Object.assign(App.data(), window.__INITIAL_STATE__);
}

new Vue({
  render: h => h(App)
}).$mount('#app');

优化SSR场景下异步数据加载带来的性能开销

  1. 代码分割:将异步数据加载的逻辑分割成单独的chunk,避免初始加载时加载过多代码。
  2. 缓存:在服务端和客户端都可以使用缓存机制,对于频繁请求的数据,避免重复请求。例如,在服务端可以使用内存缓存(如node-cache),在客户端可以使用浏览器本地缓存(localStorage)或会话缓存(sessionStorage)。
  3. 并发请求:如果有多个异步数据请求,可以使用Promise.all将它们并发执行,减少整体的等待时间。

并发请求示例代码

export default {
  data() {
    return {
      user: null,
      posts: []
    };
  },
  async created() {
    const userPromise = axios.get('/api/user');
    const postsPromise = axios.get('/api/posts');

    try {
      const [userResponse, postsResponse] = await Promise.all([userPromise, postsPromise]);
      this.user = userResponse.data;
      this.posts = postsResponse.data;
    } catch (error) {
      console.error('Error fetching data:', error);
    }
  }
};