初步认识前端SSR(服务端渲染)

背景知识

  • 最初的php,jsp等技术是曾经主流的前后端不分离的解决方案。当服务器接收到一个请求后,根据一定的逻辑,获取数据库的数据,然后把运算好的数据传递到html模板文件,生成完整的html代码,返回到客户端展示。

  • 前端框架(Vue,React等)是前后端分离思想的优秀产物。它们常见都是生成SPA应用。而SPA的优点是用户体验好,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染。

  • 前端SSR方案结合了MPA和SPA的思想,针对spa首屏加载较慢和不利于seo的缺点,采用了服务端客户端同构的方案。

关键知识点

  • 服务端客户端同构
  • 服务端渲染(SSR)
  • 静态生成(SSG)

渲染方式与spa的差异

js 复制代码
// react JSX渲染
function Hello() {
  return <div>Hello world</div>
}

export default Hello

spa页面例子(蓝湖):

ssr例子(百度):

  • spa应用的特点是依赖 JS 运算生成对应的 DOM 节点, html 文件里本来是不存在具体的DOM节点。而 SSR 是可以在服务器渲染好完整的DOM结构再返回给客户端。

生命周期与spa的差异

  • 服务端渲染时候执行的生命周期顺序和客户端渲染是一致的,但是需要注意是在服务端执行的生命周期钩子内,是无法执行浏览器特有的api

特有的渲染方法(以next.js框架为例)

静态生成(SSG)

出于性能原因,Next官方更推崇使用静态生成。 如果页面没有数据请求,Next会采用静态生成的方式,在构建的时候就生成好对应HTML;

如果页面内容依赖外部数据,可以在页面组件中export一个名叫getStaticProps的方法,这个函数会在构建时被调用,然后将获取的数据传递到页面的props中,进行预渲染;

js 复制代码
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// This function gets called at build time
export async function getStaticProps() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}

export default Blog

服务端渲染(SSR)

通常面对更新比较快,或者跟用户信息相关的页面,我们都不能使用静态生成的方式来提前生成页面,此时就需要使用服务端渲染,每次请求都重新生成页面HTML;要对页面使用服务器端渲染,需要名为getServerSideProps的方法, 服务器将在每次请求时都会调用此函数

javascript 复制代码
function Page({ data }) {
  // Render data...
}

// This gets called on every request
export async function getServerSideProps() {
  // Fetch data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // Pass data to the page via props
  return { props: { data } }
}

export default Page

getServerSideProps跟之前静态生成用到的getStaticProps方法非常相似,不同之处在于getServerSideProps在每个请求都会运行,而getStaticProps是在构建时运行。

增量生成(ISR)

SSG这种静态页面虽然好,但缺点也十分突出,如果只能在构建时生成页面,那就意味着,每次在管理后台里改动了业务数据,都需要重新构建以刷新页面。如果没有办法解决这个缺点,SSG虽好,但可使用的业务场景也非常少,所幸,next提供了在构建站点后创建或更新静态页面的能力,这就是ISR。

服务端客户端同构的工作方式

如上介绍,服务端会预先生成需要展示的html结构,那是不是就意味着每次在浏览器输入不同的url,都会访问一次服务器获取新的html内容呢?

如果是这样,就牺牲了spa的特性。所以当访问一个新的url,需要先区分是否由客户端路由跳转产生的访问,如果是则执行spa路由跳转的逻辑,否则就执行产生一条服务端请求最新的html文件内容。这就意味着同一份代码既有可能在服务端执行,也有可能在客户端执行。

SSR优点

  • 利于seo优化,方便搜索引擎抓取数据。
  • 服务端和客户端分工明确,仍保留客户端路由管理,全局数据状态管理等功能。
  • 大幅提高页面访问性能。

在这里,我主要想展开说说为什么可以明显地提升性能。

  1. 把依赖接口的数据提前在服务端获取,节省了等待接口响应的时间。
  2. 获取到了接口数据,根据特定逻辑渲染成真正的DOM结构。这个步骤也放到了服务端执行,节省客户端渲染时间。(客户端机型性能差的时候尤其明显)
  3. 浏览器加载资源,无需等待任何JS文件的加载,就可以渲染出初始页面,LCP和FCP性能指标很好。(客户端网络差的时候尤其明显)

疑问点

  • Q. 现在的前端SSR和以前的PHP等前后端不分离技术方案有何区别?

A. 前后端是否真正解耦,前端是否具备工程化能力(路由管理,全局数据状态管理,前端生态工具链)

  • Q. 使用了nuxt.js或者next.js搭建的项目后,引入一些第三方的库或组件,会报错

A. 一些三方库使用了window,localStorage等客户端特有的对象,如果该逻辑是在服务端运行的,那么这些对象肯定是为空值,所以就报错了。解决方案也不复杂,使用条件控制渲染组件,在特定的生命周期再允许渲染该组件。

总结

从以前的前后端不分离的后端语言渲染html,到spa应用,再到目前的前端SSR解决方案,历史是在螺旋上升的。前端技术方案也越来越成熟,处理大型项目的能力也越来越强大。

相关推荐
mldong4 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排5 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60615 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角6 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!6 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰7 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi8 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen9 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马9 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒10 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端