將函式作為引數傳遞解決非同步問題

rexkentzheng發表於2018-11-08

時間:2018年11月06日
這兩天有這樣的一個需求:在下載按鈕上加一個下載中的loading動畫。現在的情況是使用者點選下載按鈕時沒有一點反饋,以為沒點上,會點選好幾次,之後一下就下載好幾次。
這種問題是人之常情,所以解決它無可厚非,可是解決的時候遇到了一些比較麻煩的問題。
下載函式在點選執行按鈕執行函式呼叫的別的檔案的方法,就像下面這樣:

// a檔案
// 點選按鈕執行的函式
const main = () => {
  downloadFile()
}
// b檔案
// 具體下載函式
const downloadFile = () => {
  // 下載部分程式碼
}
複製程式碼

如果僅僅是這樣還好,我可以在main函式中加上修改是否展示載入動畫的變數,比方說下面這樣:

// a檔案
// 點選按鈕執行的函式
const main = () => {
  loading = true;
  downloadFile();
  loading = false;
}
複製程式碼

可是這個downloadFile函式是個非同步函式,所以如果想上面這樣寫的話loading變數只會瞬間變一下,不會在downloadFile函式執行完成之後再變成false
一開始我是打算用promise來把main函式包裹起來,在then裡面把loading改成false。事實證明這種方法確實可行,只是需要把reslove傳遞過去,比方說這樣:

// a檔案
// 點選按鈕執行的方法
return new Promise((reslove) => {
  const main = () => {
    loading = true;
    downloadFile(reslove);
    loading = false;
  }
})
// b檔案
const downloadFile = (reslove) => {
  // 下載部分程式碼
  reslove();
}
複製程式碼

後來思考之後發現這樣的做法其實有點多餘,完全可以不用Promise的。我們需要新建一個修改loading值的函式。

setLoadingStatus = (err, status) => {
  if (err) {
    message.error(err.message || err);
    return this.exportTableLoading = false;
  }
  this.exportTableLoading = status;
}
複製程式碼

呼叫方法也比較簡單:

// 有錯
setLoadingStatus(err, false);
// 沒錯
setLoadingStatus(null, true);
複製程式碼

之後我們把這個方法作為引數傳遞給downloadFile函式,在downloadFile函式中呼叫方法即可。

// b檔案
const downloadFile = (setLoadingStatus) => {
  // 下載部分程式碼
  if (err) {
    setLoadingStatus(err, false);
  }
  setLoadingStatus(null, true);
}
複製程式碼

這裡我們不用擔心說setLoadingStatus函式被呼叫兩次,因為如果有錯,在執行setLoadingStatus函式錯誤情況時,就會直接return錯誤內容,就算下面有接收到setLoadingStatus函式的正確情況也不會執行。
所以整體下來就是這樣的:

// a檔案
// 定義修改loading的函式
setLoadingStatus = (err, status) => {
  if (err) {
    message.error(err.message || err);
    return this.exportTableLoading = false;
  }
  this.exportTableLoading = status;
}
// 點選按鈕執行的函式
const main = () => {
  loading = true;
  downloadFile(setLoadingStatus);
}
// b檔案
const downloadFile = (setLoadingStatus) => {
  // 下載部分程式碼
  if (err) {
    setLoadingStatus(err, false);
  }
  setLoadingStatus(null, true);
}
複製程式碼

不同檔案之間也可以互相呼叫函式,不用考慮傳遞過去之後就無法修改loading值的問題,因為其本身呼叫的還是a檔案中的setLoadingStatus函式。

相關文章