SoFunction
Updated on 2025-04-06

Project-based server-side performance optimization and error detection (fault-tolerant processing)

It is a server-side rendering application framework. Some points that need to be considered when developing isomorphic projects are summarized as follows:

1. Node server-side performance optimization (improve the ability of node applications to handle high traffic)

The following points can be used to optimize the server-side performance of the server-side rendering project (it should be noted that persistent cache should not be done in the local development environment, so that the local development code problems will not be exposed during the cache)

Optimization point Reference documents and ideas Optimize scenarios/conditions Special Note Detection method
1. Page cache vue official document Page content is not user-specific (i.e., for the same URL, the same content is always rendered for all users) Generally speaking, if a page is cached on the server, then the component cache of the corresponding page's API cache is meaningless. When the page cache and the API cache exist at the same time (it may exist), the API cache time should be smaller than the page cache time, so that the content of the API response is kept up to date. 1. Code local test: Print the test log in asyncData. After the page is cached, the server will not output the test log after refreshing the page; 2. Compare the DOMContentLoaded time of the html page loading. Refresh the page and see that the cached value is smaller than the first page loading (not cached) value.
2. API cache Do it in axios request and response interceptor The interface response content is not user-specific (i.e. for the same API interface URL, that is, the same content is always responded to all users) The general request method is GET API request Comparison of the response time of the first request with the cached API interface
3. Component Cache nuxtjs official website document vue official website document Subcomponents that do not depend on global state and do not have side effects on rendering contexts The component name value to be cached must be unique, and the serverCacheKey is the unique key based on the value of a certain prop. The detection method is the same as the page cache detection method, which may be almost impossible to detect.
4. AsyncData function optimization In this function, there are more than 1 API interfaces requested, and the most are even more than 10,20. In this case, we cannot use async await. After requesting one, we will then request the next one (synchronous request interface); if there are 10 interfaces that need to request, each interface responds to an average of 1s, then it will take at least 10s to respond to the html page; if 10 interfaces are used to request 10, then the html page is closest to the 1s response time; The asyncData function will execute code on the server, so it must be fault-tolerant; in addition, if the function code has not been executed, the page response will be suspended for the first time and is always loading. For the first time the page is loaded, the shorter the execution time of the function, the shorter the page response time (the faster the page loads)

1. Page cache function module implementation

We create a file in the project root directory ~/serverMiddleware/

import LRUCache from 'lru-cache'

const cache = new LRUCache({
 maxAge: 1000 * 60 * 2, // Valid for 2 minutes max: 1000 // Maximum cache number})

export default function(req, res, next) {
 // The local development environment does not perform page cache if (.NODE_ENV !== 'development') {
 try {
  const cacheKey = 
  const cacheData = (cacheKey)
  if (cacheData) {
  return (cacheData, 'utf8')
  }
  const originalEnd = 
   = function(data) {
  (cacheKey, data)
  (res, ...arguments)
  }
 } catch(error) {
  // (`page-cache-middleware: ${error}`)
  next()
 }
 }
 next()
}

2. Api cache function module implementation

We create two files in the root directory of the project ~/plugins/axios/ and ~/plugins/axios/ respectively; the special trick is that the development environment plug-in code is refreshed on the page and the routing switch is equivalent to the first run, so you will find that the cache function is invalid, and it is only valid in the .NODE_ENV === 'production' production environment

// ~/plugins/axios/

import md5 from 'md5'

/**
  * According to the request configuration, whether it is a request interceptor Create a cache key
  * @param {Object} config
  * @param {Boolean} isRequest
  */

export default function createCacheKey(
 config = {},
 isRequest = false
) {
 const {
 url,
 data,
 params,
 method,
 baseURL,
 } = config || {}

 let commonUrl = url

 /**
  * The baseURL is not spliced ​​in the request interceptor, and the baseURL is spliced ​​in the response interceptor.
  * In order to maintain uniformity, use the commonUrl of the unified splicing baseURL; pay attention to the following if condition judgment
  */
 if (isRequest && !(baseURL) && !(/^https?/)) {
 commonUrl = !!(/.+\/$/) ? `${(/\/$/, '')}${url}` : `${baseURL}${url}`
 }

 // Generate rules according to request instructions, url, body body, parameter const rule = `method=${method}-url=${commonUrl}-data=${(data || {})}-params=${(params || {})}`

 // md5 encryption return md5(rule)
}

// ~/plugins/axios/

import LRUCache from 'lru-cache'
import axios from 'axios'
import globalConfig from '../../global-config'
import createCacheKey from './createCacheKey'

const cache = new LRUCache({
 maxAge: 1000 * 60, // Valid for 60 seconds. If there is a page cache, the API cache time should be smaller than the page cache time, so that the content of the API response is kept up to date. max: 1000 // Maximum cache number})

/**
  * matchCacheCondition meets the persistent cache conditions: server runtime && non-local development environment && api request is the get request method
  * @param {Object} config Request configuration
  */
function matchCacheCondition(config = {}) {
 return  && .NODE_ENV !== 'development' && () === 'get'
}

/**
  * If all pages are cached, the API cache is not necessary
  */
export default function({ $axios, redirect }) {
 $(config => {
 const { baseUrl } = globalConfig
  = baseUrl[] || baseUrl['other']

 // Return config directly if the cache condition is not met if (!matchCacheCondition(config)) {
  return config
 }

 const cacheKey = createCacheKey(config, true)
 const cacheData = (cacheKey)

 if (cacheData) {
  const source = ()
   = 
  ({ cacheData, cacheKey, url:  })
  return config
 }

 return config
 })

 $(response => {
 if (matchCacheCondition()) {
  (createCacheKey(), response)
 }
 return response
 }, (error) => {
 if ((error) && matchCacheCondition()) {
  // (`The interface url cached in the current page component asyncData or fetch function is: ${}`)  return ()
 }

 // Server prints the API interface request error log if () {
  try {
  const {
   config: {
   url
   },
   message
  } = error || {}
  (`askurl:${url},Error message:${message}`)
  } catch(error) {
  // (error)
  }
 }

 // The server and client unified the reject error object, so the page component asyncData and fetch function must handle the API interface to request the AsyncData interface. return (error)
 })
}

3. Component cache

Original words of vue official website document: If the renderer makes a cache hit during component rendering, it will directly reuse the cached results of the entire subtree. This means that you should not cache components in the following situations:

  • It has subcomponents that may depend on global state.
  • It has a subcomponent that has side effects on the rendering context.

Therefore, you should be careful to use component caching to resolve performance bottlenecks. In most cases, you should not and do not need to cache single instance components. The most common type of component that works for caches is a component that appears repeatedly in large v-for lists. Since these components are usually driven by objects in database collections, they can use a simple cache strategy: use their unique id, plus the last updated timestamp to generate their cache key:

serverCacheKey: props =>  + '::' + .last_updated

4. Optimization of page component asyncData function

Give a simple example to optimize

{
 async asyncData({ $axios }) {
 // 1. Add catch processing to enable the server and the client to not report errors when running, especially to prevent the server from reporting errors when running, otherwise the page will hang up. // 2. The catch function returns a Promise of a resolve empty literal object, indicating that the state of dataPromise1 will always be resolved in the future. const dataPromise1 = $('/api/data1').catch(() => ({}))

 const dataPromise2 = $('/api/data2').catch(() => ({}))
 const dataPromise3 = $('/api/data3').catch(() => ({}))
 const dataPromise4 = $('/api/data4').catch(() => ({}))
 const dataPromise5 = $('/api/data5').catch(() => ({}))
 const dataPromise6 = $('/api/data6').catch(() => ({}))
 const dataPromise7 = $('/api/data7').catch(() => ({}))
 const dataPromise8 = $('/api/data8').catch(() => ({}))

 // Ensure that apiData has data const apiData = await new Promise(resolve => {
  ([
  dataPromise1, dataPromise2, dataPromise3, dataPromise4,
  dataPromise5, dataPromise6, dataPromise7, dataPromise8,
  ])
  .then(dataGather => {
   resolve({
   data1: dataGather[0],
   data2: dataGather[1],
   data3: dataGather[2],
   data4: dataGather[3],
   data5: dataGather[4],
   data6: dataGather[5],
   data7: dataGather[6],
   data8: dataGather[7],
   })
  })
 })

 return apiData
 }
}

2. Node server-side error detection and fault tolerance processing (improve the node application's ability to handle fault tolerance)

First, make sure to use the framework. The following functions in the vue component (page/non-page component) will be executed on the server side, so code tolerance is very important. Once the function code execution error occurs, the page will hang up.

  • fetch
  • asyncData
  • beforeCreate
  • created

1. The error of seeing

The error you can see means that in the development environment, if you just execute the error in the js in the above functions such as fetch, there will be error prompts locally, which will facilitate you to find and correct the error code logic.

2. Unknown/invisible errors (expose unknown errors)

Invisible errors mean that some error codes in asynchronous callbacks are not easily discovered. If the asynchronous behavior has not been triggered, the callback code that handles the asynchronous behavior will not be executed; however, for error checking of API interface request callbacks for all pages (mainly for fault tolerance processing, making the code more robust, Java interface request 404, interface data fields/structure processing) we can do it well, it is very simple. We only need to change the request url in the request interceptor.

$(config => {
 // TODO
 // Detect node application errors caused by failed requesting java interface  += '/xxxx'

 return config
})

3. Processing of page refresh loading data that does not require rendering

Only after the page component asyncData (the object returned by the function is merged with the component data), the data processed by the fetch (update store operation) function is bound to the page, the page refresh and loading server will be rendered. Therefore, it is not recommended that the component obtain the page refresh and load data that does not need to be rendered by requesting the API interface in the beforeCreate and created functions. It only needs to be processed in the mounted function to prevent node application errors due to code errors.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.