2013-01-04 81 views
4

假設我想發送一封電子郵件,然後更新數據庫,這兩個操作都是異步的。這是我通常會寫的。我可以用什麼來取代嵌套的異步回調?

send_email(function(err, id){ 
    if(err){ 
     console.log("error"); 
    }else{ 
     update_database(id,function(err, id){ 
      if(err){ 
       console.log("error"); 
      }else{ 
       console.log("success"); 
      } 
     }); 
    } 
}); 

我想用中間件代替它。

var mid = {}; 

mid.send_email = function(){ 
    return function(next){ 
     send_email(function(err,id){ 
      if(err){ 
       console.log("error"); 
      }else{ 
       next(id); 
      } 
     }); 
    } 
} 

mid.update_database = function(){ 
    return function(id,next){ 
     update_database(id,function(err,id){ 
      if(err){ 
       console.log("error"); 
      }else{ 
       next(id); 
      } 
     }); 
    } 
} 

mid.success = function(){ 
    return function(id,next){ 
     console.log("success") 
     next(id); 
    } 
} 

堆疊中間件。

middleware.use(mid.send_email()); 
middleware.use(mid.update_database()); 
middleware.use(mid.success()); 

有兩個主要問題在手。

  • 如何使用中間件代替嵌套回調?
  • 是否可以將變量傳遞給next()
+0

這被稱爲「排隊」 – zzzzBov

+1

不清楚你的文章中的「中間件」是指某個特定的庫還是「一個可以幫助你的庫」。標籤「中間件」絕對沒有特定於JavaScript的東西。 –

+0

@AlexeiLevenkov我明白你的觀點。我使用了「中間件」這個詞,因爲那是什麼技術。但我也不確定是否有圖書館。 – ThomasReggi

回答

5

你想要的是能夠處理異步控制流。許多js庫可以幫助你實現這一目標。您可以用waterfall功能嘗試Async庫,因爲你希望能夠將變量傳遞給將要執行的下一個功能:

https://github.com/caolan/async#waterfall

「運行的串聯功能的陣列,每過他們的結果到數組中的下一個,但是,如果任何函數將錯誤傳遞給回調函數,則不會執行下一個函數,並立即調用主回調函數並返回錯誤。

例子:

async.waterfall([ 
    function(callback){ 
     callback(null, 'one', 'two'); 
    }, 
    function(arg1, arg2, callback){ 
     callback(null, 'three'); 
    }, 
    function(arg1, callback){ 
     // arg1 now equals 'three' 
     callback(null, 'done'); 
    } 
], function (err, result) { 
    // result now equals 'done'  
}); 
1

你可能最好使用CommonJS module.exports。在server.js

module.exports = function(){ 
    function sendEmail(doneCallback){ 
     // do your stuff, then when you are done: 
     if(!err){ 
      doneCallback(whatever,args,you,need); 
     } 
    } 

    function updateDB(success){ 
     // do your stuff, then when you are done: 
     success(whatever,args,you,need); 
    } 

    return { 
     send: sendEmail, 
     update: updateDB 
    }; 
}; 

然後:

您可以創建這樣一個文件

var lib = require('./mylib.js'); 

lib.send(function(result){ 
    console.log(result); 
}); 

這是一個類似的模式,以及它可能給你什麼,我的意思是一個更好的主意。它由庫烤function並將它傳遞給任何需要到連鎖,像這樣的(更腳踏實地例如,客戶端這個時間):

ui.bistate($('#mybutton'), function(restore){ 
    $.ajax({ 
     url: '/api/1.0/catfood', 
     type: 'PUT', 
     data: { 
      catfood: { 
       price: 1.23, 
       name: 'cheap', 
       text: 'Catzy' 
      } 
     } 
    }).done(function(res){ 
     // stuff with res 
     restore(); 
    }); 
}); 

,並在圖書館,這是多麼restore是提供:

var ui = function(){ 
    function bistate(button, action) { 
     var originalText = buttonText.data('text'), 
      disabledText = buttonText.data('text-disabled'); 

     function restore(){ 
      button.prop('disabled', false); 
      button.text(originalText); 
     } 

     function disable(){ 
      button.prop('disabled', true); 
      button.text(disabledText); 
     } 

     button.on('click', function(){ 
      disable(); 
      action(restore); 
     }); 
     restore(); 
    } 

    return { 
     bistate: bistate 
    }; 
}(); 

允許消費者控制的時候,他希望恢復按鈕的流動,不必處理複雜的情況下,消費者想要在這兩者之間做一個異步操作重溫庫。

一般的觀點是:經過回調來回巨大,而不是使用足夠廣泛

相關問題