回呼

回呼 在 JavaScript

2 個練習

關於 回呼

回呼函式 是作為引數傳遞給其他函式的函式。接著便可以呼叫這個回呼函式,觸發後續的動作。回呼函式經常用來處理工作完成的結果,或在事件發生時處理對應的動作。回呼函式可用於同步與非同步程式設計。

const sideLength = 5;

// Caller function takes a callback function
function applySideLength(callback) {
  return callback(sideLength);
}

// Callback must expect the possible argument from the calling function
function areaOfSquare(side) {
  return side * side;
}

applySideLength(areaOfSquare); // => 25

你也可以把回呼寫成函式運算式:

applySideLength(function squarePerimeter(side) {
  return side * 4;
});

這在 JavaScript 中是很好用的模式,因為 JavaScript 的執行環境設計成單執行緒,同一時間只能執行一次函式呼叫。在執行期間,除非函式已經回傳,否則執行環境無法回應其他事件,也無法繼續執行。

許多 API 呼叫(I/O 函式、計時器與事件監聽器)會使用非同步機制,把目前的函式呼叫擱置在一旁,直到工作完成。完成之後,回呼函式會被放進訊息佇列,這樣當執行環境介於兩次函式呼叫之間時,就會藉由呼叫回呼函式來處理這些訊息。

使用回呼函式還有一個好處:它可以參照自己閉包作用域裡的變數,而這些變數是後來呼叫它的那個函式所無法存取的。

回呼函式的具體範例

事件處理器

事件處理器是 JavaScript 中回呼的常見用途。像是 'onload' 或 'onclick' 這類瀏覽器事件,是能夠觸發函式被呼叫的訊號。DOM 的 [Document Object Model 物件,其 addEventListener 方法會註冊一個回呼函式,當它「聽到」事件發生時就會呼叫該函式。

document.addEventListener('onload', function () {
  alert('The webpage has now been loaded');
});

Node.js 慣例

在 Node.js 中,回呼函式遵循一套慣例來控制程式的流程。它們遵循這樣的模式:回呼函式的第一個引數可能會收到 Error 或 null;第二個之後的引數則會收到呼叫端函式所要傳送的資料。

如果發生錯誤,第二個之後的引數可能不存在,所以你不能依賴它們一定存在。

function operation(a, b, callback) {
  // Work ...

  if (/* an error occurs */) {
    return callback(new Error('An error occurred'))
  }

  // On success:
  callback(null, data)
}

function callback(error, returnedData) {
  if (error) {
    // An error occurred, handle it here.
    return
  }

  // No error occurred, continue with the returned data.
}

operation(1, 2, callback)

在處理非同步函式、需要協助控制流程時,你很常見到這種模式。

隱藏版的回呼

常見的Array函式會用回呼函式來定義自己的行為:

  • Array.prototype.forEach:

    • 接受一個回呼,並對陣列的每個元素套用這個回呼。

      [1, 2, 3].forEach(function (element) {
        doSomething(element);
      });
      // => doSomething() is invoked 3 times, once with each element
      
  • Array.prototype.map

    • 接受一個回呼,對陣列的每個元素套用這個回呼,並用結果建立一個新陣列。

      [1, 2, 3].map(function (element) {
        return element + 1;
      });
      // => [2, 3, 4]
      
  • Array.prototype.reduce

    • 接受一個回呼,對陣列的每個元素套用這個回呼,並把結果傳遞給下一次呼叫。

      [1, 2, 3].reduce(function (runningSum, element) {
        return runningSum + element;
      }, 0);
      // => 6
      
透過 GitHub 編輯 連結會在新視窗或分頁中開啟

學習 回呼