近期項目總結

最近項目事情很多,開發過程中也碰到了很多值得記錄的問題,今天就早點來公司,把最近一些問題和經驗總結一下,以便以後進行參考。

JS數值精度丟失

這其實是一個衆所周知的問題,但他本身並不是js的bug,js採用的是IEEE 754 規範,採用雙精度存儲(double precision),佔用 64 bit。所以這個BUG並不是只有js有,只要是採用了這個規範的語言都會有這個問題。
JS 中能精準表示的最大整數是 Math.pow(2, 53),十進制即 9007199254740992。所以當數值大於該值時就會出現精度丟失。在項目中後端傳給前端的ID是數值並且超過了最大數值,最後導致了精度的丟失,當時也是找了很久才發現是這個原因,對於這個問題前端並沒有很好的解決辦法,只能是由後端將數值轉爲字符串傳給前端解決問題。

async的使用

這是ES2017標準中引入的一個函數,其實並不是很新的東西,已經很多人在使用了,但是我一直還停留在使用promise的階段,這次項目中碰見了需要加載很多圖片,然後進行壓縮的情況,想起來用async應該會很方便,然後就用上了,代碼確實簡介了不少,增強了代碼的可讀性,比起回調和promise又更加方便了一點。
async函數返回一個 Promise 對象,可以使用then方法添加回調函數。當函數執行的時候,一旦遇到await就會先返回,等到異步操作完成,再接着執行函數體內後面的語句。任何一個await語句後面的 Promise 對象變爲reject狀態,那麼整個async函數都會中斷執行。
await命令後面的Promise對象,運行結果可能是rejected,所以最好把await命令放在try…catch代碼塊中。

async function myFunction() {
  try {
    await somethingThatReturnsAPromise();
  } catch (err) {
    console.log(err);
  }
}

// 另一種寫法

async function myFunction() {
  await somethingThatReturnsAPromise()
  .catch(function (err) {
    console.log(err);
  });

多個await命令後面的異步操作,如果不存在繼發關係,最好讓它們同時觸發。

let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 寫法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

await命令只能用在async函數之中,如果用在普通函數,就會報錯。也就是說不能用在foreach函數中,可以用for循環代替。

async function dbFuc(db) {
  let docs = [{}, {}, {}];

  // 報錯
  docs.forEach(function (doc) {
    await db.post(doc);
  });
}
//正確寫法
async function dbFuc(db) {
  let docs = [{}, {}, {}];

  for (let doc of docs) {
    await db.post(doc);
  }
}

用上述的寫法發送請求所有遠程操作都是繼發。只有前一個 URL 返回結果,纔會去讀取下一個 URL,這樣做效率很差,非常浪費時間。我們需要的是併發發出遠程請求。項目裏需要請求上百張圖片,然後對返回的圖片壓縮成zip包,之前就是用上述的方法進行壓縮,效率真的很差,後面看到了阮一峯老師的寫法,頓時感覺大神就是不一樣。

async function compressionImage(imgUrlArray, id) {
    const zip = new JSZip()

    //併發發出遠程請求。
    const result = imgUrlArray.map(async url => {
      const response = await props.getImageStream(url.material_path)
      return { url: url.material_path, response }
    })

    //按順序輸出。
    for (const elementPromise of result) {
      const temp = await elementPromise
      zip.file(temp.url, temp.response)
    }

    const content = await zip.generateAsync({ type: 'blob' })
    let temp = formData
    temp[id] = content
    setFormData(temp)
  }

react清空state

這個其實算不上什麼難點和問題,當你在請求中使用setState時,由於請求是異步的,所以在你退出組件的時候可能請求還沒有發完,這時候就有可能還會調用setState,所以需要在退出組件的時候清空state,之前react用的是class的寫法,現在已經用react hook寫了,在react hook中清空的寫法與之前有些不同:

  useEffect(() => {
    if (!props.hideEdit) {
      computerMaterialSize(dataSet.materials || [])
    }
    
    return () => {
      setMaterialsSize = () => {
        return
      }
    }
  }, [])

這個寫法其實並不是很好,如果你有很多個setState的話,你就得一個個return,可能是現在用hook的人並不是很多,所以也沒有看到更好的寫法,如果有的話,還請指點一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章