是否有更好的异步编码模式?

时间:2017-03-15 05:33:08

标签: javascript node.js

如果我只有同步功能并且:

var err = f1();
if (err)
   xxxx
else
   yyyy;

我需要添加另一个函数调用,该调用依赖于第一个成功完成的函数,我可以追加它:

var err = f1(a);
if (err)
   xxxx
else {
   yyyy;

   var err2 = f2(b);
   if (err2)
      ...
   else
      rrr;
}

但是当函数是异步的时候,我最初会:

f1(a, function(err) {
   if (err)
      xxxx
   else 
      yyy;
});

添加第二个调用需要一些手术,大量的括号和括号来追踪:

f1(a, function(err) {
   if (err)
      xxxx
   else {
      yyy;
      f2(b, function(err) {
        if (err)
          ...
        else
          rrr;
      });
   }
});

添加第三个更加痛苦和耗时。我错过了一个更聪明的方法吗?

2 个答案:

答案 0 :(得分:1)

我更喜欢承诺模式。

var firstMethod = function() {
   var promise = new Promise(function(resolve, reject){
      setTimeout(function() {
         console.log('first method completed');
         resolve({data: '123'});
      }, 2000);
   });
   return promise;
};


var secondMethod = function(someStuff) {
   var promise = new Promise(function(resolve, reject){
      setTimeout(function() {
         console.log('second method completed');
         resolve({newData: someStuff.data + ' some more data'});
      }, 2000);
   });
   return promise;
};

var thirdMethod = function(someStuff) {
   var promise = new Promise(function(resolve, reject){
      setTimeout(function() {
         console.log('third method completed');
         resolve({result: someStuff.newData});
      }, 3000);
   });
   return promise;
};

firstMethod()
   .then(secondMethod)
   .then(thirdMethod);

(无耻地复制:https://html5hive.org/how-to-chain-javascript-promises/

一旦你达到5-6个函数,它就会更好地扩展,看起来比嵌套更好。

这假设你想按顺序执行一个接一个的功能。如果您不关心执行顺序,但只是想确保所有异步调用都已完成,那么我会看一下 $ .deferred 模式(jQuery)。这样可以确保如果你有N个异步函数,并且希望N + 1函数在完成后执行,那么你就有了一个干净的方法。

示例:

var name = $.post('/echo/json/', {json:JSON.stringify({'name':"Matt Baker"})});
var lastUpdate = $.post('/echo/json/', {json:JSON.stringify({'lastUpdate':"Hello World"})});

$.when(name, lastUpdate)
    .done(function (nameResponse, lastUpdateResponse) {
        var name = nameResponse[0].name;
        var lastUpdate = lastUpdateResponse[0].lastUpdate;
        $("#render-me").html(name+"'s last update was: "+lastUpdate);
    })
    .fail(function () {
        $("#error").html("an error occured").show();

http://eng.wealthfront.com/2012/12/04/jquerydeferred-is-most-important-client/

复制无耻#2

我在UI初始化中使用#2nd方式,当几个列表框,下拉列表和任何异步初始化时,并且确保在所有asyncs完成后启用用户界面。为什么不同步你问?为了更好地利用浏览器可以使用的多个http请求。它更快。

答案 1 :(得分:0)

如果您的功能返回承诺,并且您定位的环境支持async / await,那么代码几乎不需要更改:

var err = await f1(a);
if (err)
   xxxx
else {
   yyyy;

   var err2 = await f2(b);
   if (err2)
      ...
   else
      rrr;
}