面试题答案
一键面试SSR场景下异步数据加载在Vue生命周期钩子中的实现
在SSR场景下,通常会在created
或beforeMount
钩子中进行异步数据加载。由于服务端渲染没有真实的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>
处理服务端和客户端数据一致性问题
- 预取数据:在服务端渲染时,我们可以在渲染组件之前,提前获取异步数据,并将数据注入到组件的状态中。这样,客户端渲染时可以直接使用服务端已经获取到的数据,避免重复请求。
- 使用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场景下异步数据加载带来的性能开销
- 代码分割:将异步数据加载的逻辑分割成单独的chunk,避免初始加载时加载过多代码。
- 缓存:在服务端和客户端都可以使用缓存机制,对于频繁请求的数据,避免重复请求。例如,在服务端可以使用内存缓存(如
node-cache
),在客户端可以使用浏览器本地缓存(localStorage
)或会话缓存(sessionStorage
)。 - 并发请求:如果有多个异步数据请求,可以使用
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);
}
}
};