Javascript callbacks

Callback 到底是什麼呢? 當一個函式執行完畢後所執行的那個函式就是所謂的 callback 函式. 聽起來滿饒舌的齁. 一般來說如果你想讓 do_bdo_a 之後執行程式大概會長得這個樣子

function do_a(){
  console.log( '`do_a`: 這會先出現');
}

function do_b(){
  console.log( '`do_b`: 跟著才是這個' );
}

do_a();
do_b();
結果
`do_a`: 這會先出現
`do_b`: 跟著才是這個

但是因為 javascript 是一個事件驅動的語言. 所以如果當 do_a 所花的時間比 do_b 久的話, do_b 的結果就會比 do_a 早出來.

function do_a(){
  // 模擬一個需要長間的 function
  setTimeout( function(){
    console.log( '`do_a`: 這個需要的時間比 `do_b` 長' );
  }, 1000 );
}

function do_b(){
  console.log( '`do_b`: 這本來應該出現在 `do_a` 之後但是卻先出現了' );
}

do_a();
do_b();
結果
`do_b`: 這本來應該出現在 `do_a` 之後但是卻先出現了
`do_a`: 這個需要的時間比 `do_b` 長

所以我們要怎麼確定讓 do_b 出現在 do_a 之後呢? 這時候 callbacks 就派上用場了.

function do_a( callback ){
  setTimeout( function(){
    // 模擬一個需要長間的 function
    console.log( '`do_a`: 這個需要的時間比 `do_b` 長' );

    // 如果 callback 存在的話就執行他
    callback && callback();
  }, 3000 );
}

function do_b(){
  console.log( '`do_b`: 現在我們就可以肯定 `do_b` 出現在 `do_a` 之後了' );
}

do_a( function(){
  do_b();
});
結果
`do_a`: 這個需要的時間比 `do_b` 長
`do_b`: 現在我們就可以肯定 `do_b` 出現在 `do_a` 之後了
各種不同套用 callback 的方式
function basic( callback ){
  console.log( '作些事情' );

  var result = '我是等會要被傳送給 `do something` 的 callback 的函式結果';

  // 如果 callback 存在的話就執行他
  callback && callback( result );
}

function callbacks_with_call( arg1, arg2, callback ){
  console.log( '作些事情' );

  var result1 = arg1.replace( 'argument', 'result' ),
      result2 = arg2.replace( 'argument', 'result' );

  this.data = '這等會可以讓 callback 函式用 `this` 來調用';

  // 如果 callback 存在的話就執行他
  callback && callback.call( this, result1, result2 );
}

// 這個和 `callbacks_with_call` 很相像
// 唯一不同點是將 `call` 換成了 `apply`
// 所以參數只能傳陣列
function callbacks_with_apply( arg1, arg2, callback ){
  console.log( '作些事情' );

  var result1 = arg1.replace( 'argument', 'result' ),
      result2 = arg2.replace( 'argument', 'result' );

  this.data = '這等會可以讓 callback 函式用 `this` 來調用';

  // 如果 callback 存在的話就執行他
  callback && callback.apply( this, [ result1, result2 ]);
}

basic( function( result ){
  console.log( '這個 callback 函式會在 terminal 上列出 `basic` 函式執行的結果' );
  console.log( result );
});

console.log( '--------------------------------------------------------------------------------------' );

( function(){
  var arg1 = '我是 argument1',
      arg2 = '我是 argument2';

  callbacks_with_call( arg1, arg2, function( result1, result2 ){
    console.log( '這一個 callback 函式將會列出 `callbacks_with_call` 的執行結果' );
    console.log( 'result1: ' + result1 );
    console.log( 'result2: ' + result2 );
    console.log( 'data from `callbacks_with_call`: ' + this.data );
  });
})();

console.log( '--------------------------------------------------------------------------------------' );

( function(){
  var arg1 = '我是 argument1',
      arg2 = '我是 argument2';

  callbacks_with_apply( arg1, arg2, function( result1, result2 ){
    console.log( '這一個 callback 函式將會列出 `callbacks_with_apply` 的執行結果' );
    console.log( 'result1: ' + result1 );
    console.log( 'result2: ' + result2 );
    console.log( 'data from `callbacks_with_apply`: ' + this.data );
  });
})();
結果
作些事情
這個 callback 函式會在 terminal 上列出 `basic` 函式執行的結果
我是等會要被傳送給 `do something` 的 callback 的函式結果
--------------------------------------------------------------------------------------
作些事情
這一個 callback 函式將會列出 `callbacks_with_call` 的執行結果
result1: i am result1
result2: i am result2
data from `callbacks_with_call`: 這等會可以讓 callback 函式用 `this` 來調用
--------------------------------------------------------------------------------------
作些事情
這一個 callback 函式將會列出 `callbacks_with_apply` 的執行結果
result1: i am result1
result2: i am result2
data from `callbacks_with_apply`: 這等會可以讓 callback 函式用 `this` 來調用

現在我們知道如何執行 node.js 的程式, 如何使用 requireexports, function scopes 以及 closures 還有 callbacks 的重要性. 接下來我們來看看 node.js 裡最重要的東西 – 事件


Related posts