请求前置-优化

76 阅读1分钟

前言

最近在学习react,所以本次例子用react书写,写的不好请见谅。

先说需求

绘制一个海报页面,有文字图片等内容,有个二维码图片url需要通过接口获取

再上代码

function App() {
  const getQRcodeUrl = () =>
    new Promise(resolve => {
      setTimeout(() => {
        resolve(
          'https://img2.baidu.com/it/u=3202947311,1179654885&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500'
        )
      }, 1000)
    })
  useEffect(() => {
    ;(async () => {
      const canvas = document.getElementById('canvas')
      const ctx = canvas.getContext('2d')
      // 第一步 写文字
      ctx.fillText('hello', 0, 20)
      // .... 很多步骤
      // 绘制背景
      const QRcodeUrl = await getQRcodeUrl()
      const img = new Image()
      img.crossOrigin = 'anonymous'
      img.onload = () => {
        ctx.drawImage(img, 0, 50, 50, 50)
      }
      img.src = QRcodeUrl
      // .... 很多步骤
    })()
  }, [])
  return <canvas id="canvas" width="100" height="100" />
}

以下是页面展示效果

image.png

请求前置

如果getQRcodeUrl接口很慢,那么后续的绘制步骤统统会delay。现在我们把获取url的接口改为页面初始化"created"时候就执行


function App() {
  const getQRcodeUrl = useCallback(
    () =>
      new Promise(resolve => {
        setTimeout(() => {
          resolve(
            'https://img2.baidu.com/it/u=3202947311,1179654885&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500'
          )
        }, 1000)
      }),
    []
  )
  const getQRcodeUrlPromise = useRef()
  useEffect(() => {
    getQRcodeUrlPromise.current = getQRcodeUrl()
  }, [getQRcodeUrl])
  useEffect(() => {
    ;(async () => {
      const canvas = document.getElementById('canvas')
      const ctx = canvas.getContext('2d')
      // 第一步 写文字
      ctx.fillText('hello', 0, 20)
      // .... 很多步骤
      // 绘制背景
      const QRcodeUrl = await getQRcodeUrlPromise.current
      const img = new Image()
      img.crossOrigin = 'anonymous'
      img.onload = () => {
        ctx.drawImage(img, 0, 50, 50, 50)
      }
      img.src = QRcodeUrl
      // .... 很多步骤
    })()
  }, [])
  return <canvas id="canvas" width="100" height="100" />
}

好处

  • 不用我说,肯定是快
  • 如果"mounted"函数会多次执行,那么await getQRcodeUrlPromise.current只会走一次接口请求,且只有第一次可能等待时间会随着接口时间变长,后续在走进来,同Promise.resolve一样的快

弊端

  • 只能适用于请求一次,不会变更后续数据的需求
  • 代码量增加不少