javascript - 避免 javascript 回调和 promise hell

标签 javascript node.js promise

我有很多异步方法要执行,我的程序流程可能会根据每个方法的返回值发生很大变化。下面的逻辑是一个例子。我无法使用 Promises 以易于阅读的方式编写它。你会怎么写?

Ps:欢迎更复杂的流程。

Ps2:is_business 是一个预定义标志,我们在其中说明我们是在写“企业用户”还是“个人用户”。

begin transaction
update users
if updated
    if is_business
        update_business
        if not updated
            insert business
        end if
    else
        delete business
    end if
else
    if upsert
        insert user
        if is_business
            insert business
        end if
    end if
end if
commit transaction

最佳答案

promises 的好处在于它们在同步代码和异步代码之间做了一个简单的类比。举例说明(使用 Q 库):

同步:

var thisReturnsAValue = function() {
  var result = mySynchronousFunction();
  if(result) {
    return getOneValue();
  } else {
    return getAnotherValue();
  }
};

try {
  var value = thisReturnsAValue();
  console.log(value);
} catch(err) {
  console.error(err);
}

异步:

var Q = require('q');

var thisReturnsAPromiseForAValue = function() {
  return Q.Promise(function() {
    return myAsynchronousFunction().then(function(result) {
      if(result) {
        // Even getOneValue() would work here, because a non-promise
        // value is automatically cast to a pre-resolved promise
        return getOneValueAsynchronously();
      } else {
        return getAnotherValueAsynchronously();
      }
    });
  });
};

thisReturnsAPromiseForAValue().then(function(value) {
  console.log(value);
}, function(err) {
  console.error(err);
});

您只需要习惯这样的想法,即返回值始终作为 then-callbacks 的参数访问,并且链接 promise 等同于组合函数调用 (f(g(h(x)))) 或以其他方式按顺序执行函数 (var x2 = h(x); var x3 = g(x2);)。基本上就是这样!当您引入分支时,事情会变得有点棘手,但您可以从这些基本原则中找出要做什么。因为 then-callbacks 接受 promises 作为返回值,所以您可以通过为异步操作返回另一个 promise 来改变您异步获得的值,该异步操作解析为基于旧值的新值,并且父 promise 将在新的解决之前不解决!当然,您可以从 if-else 分支中返回这些 promise 。

上面示例中说明的另一个非常好的事情是 promise (至少是符合 Promises/A+ 的 promise )以同样类似的方式处理异常。 “引发”的第一个错误绕过非错误回调并冒泡到第一个可用的错误回调,很像 try-catch block 。

就其值(value)而言,我认为尝试使用手工制作的 Node.js 风格的回调和 async 库来模仿这种行为是一种特殊的 hell :)。

遵循这些准则,您的代码将变成(假设所有函数都是异步的并返回 promise ):

beginTransaction().then(function() {
  // beginTransaction() has run
  return updateUsers(); // resolves the boolean value `updated`
}).then(function(updated) {
  // updateUsers() has "returned" `updated`
  if(updated) {
    if(isBusiness) {
      return updateBusiness().then(function(updated) {
        if(!updated) {
          return insertBusiness();
        }
        // It's okay if we don't return anything -- it will
        // result in a promise which immediately resolves to
        // `undefined`, which is a no-op, just like a missing
        // else-branch
      });
    } else {
      return deleteBusiness();
    }
  } else {
    if(upsert) {
      return insertUser().then(function() {
        if(isBusiness) {
          return insertBusiness();
        }
      });
    }
  }
}).then(function() {
  return commitTransaction();
}).done(function() {
  console.log('all done!');
}, function(err) {
  console.error(err);
});

关于javascript - 避免 javascript 回调和 promise hell ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38862022/

相关文章:

javascript - 如果浏览器调整大小,如何使我的选择框在我的固定页脚溢出

javascript - C3.js : Months name are not showing continuously

javascript - 从 JavaScript 操作 CSS 的最佳实践?

javascript - 如何处理对循环中发出的多个异步请求(AJAX 调用)的响应

javascript - 如何减少 switch 语法的迭代

node.js - 在 hapi.js 的处理函数中使用 async/await 返回数据

node.js - socket.io 正在向所有房间而不是指定的房间发出信号

javascript - 如何在 Google Cloud Compute node.js getVMs 中使用正则表达式进行过滤

javascript - 履行后将 promise 数组转换为值数组

javascript - 解析函数并使用其副作用在服务中记录数据