使用承诺编写可读代码的最佳方法是什么?

What is the best way to write readable code using promises?

本文关键字:最佳 方法 是什么 代码 承诺      更新时间:2023-09-26

我有一些node.js承诺代码看起来像这样:

function myFunc(data) {
  Q(data).then(function(data) {
    return getPromise1(globalVar).then(function(res1a) {
      return getPromise2(JSON.parse(param2)).then(function(res2a) {
        return doStuff();
      }).then(function(res2b) {
        return getPromise3(data).then(function(res3a) {
          return getPromise4.then(function(res4a) {
            // more stuff
          })
        })
      })
    })
  })
})

如您所见,此代码的可读性不是很强。有没有更好的方法可以做到这一点?

如果你不需要一次获得所有结果,就不要再把承诺当作回调了:

function myFunc(data) {
  Q(data).then(function(data) {
    return getPromise1(globalVar);
  }).then(function(res1a) {
    return getPromise2(JSON.parse(param2));
  }).then(function(res2a) {
    return doStuff();
  }).then(function(res2b) {
    return getPromise3(data);
  }).then(function(res3a) {
    return getPromise4;
  }).then(function(res4a) {
    // more stuff
  })
})

如果你这样做,那么你可以尝试给定生成器函数支持的协程(Q 可能有这方面的东西,但这里有一个蓝鸟的方式):

var myFunc = bluebird.coroutine(function* myFunc(data) {
  var res1a = yield getPromise1(globalVar);
  var res2a = yield getPromise2(JSON.parse(param2));
  var res2b = yield doStuff();
  var res3a = yield getPromise3(data);
  var res4a = yield getPromise4;
  // more stuff
})

或同步检测:

function myFunc(data) {
  var res1a = getPromise1(globalVar);
  var res2a = res1a.then(function() {
    yield getPromise2(JSON.parse(param2));
  });
  var res2b = res2a.then(function() {
    // feel free to use res1a.value() here;
    // you know that it has to have been resolved
    doStuff();
  });
  // …
  return res4a;
}

除了将数据参数与控制流参数分离之外,promise的目标之一实际上是解决这个巨大的三角形代码块的问题。

function myFunc(data) {
  Q(data).then(function(data) {
    return getPromise1(globalVar);
  }).then(function(res1a) {
    return getPromise2(JSON.parse(param2));
  }).then(function(res2a) {
    return doStuff();
  }).then(function(res2b) {
    return getPromise3(data);
  }).then(function(res3a) {
    return getPromise4;
  }).then(function(res4a) {
    // more stuff
  })
}

现在,您需要嵌套承诺的唯一原因是,如果您需要在不紧随其后的函数中使用从承诺返回的数据。见下文:

doAsyncA().then(function(x) {
  doAsyncB().then(function(y) {
    doSyncUsingBothReturns(x, y);
  })
})

在您的示例中,使用 lambda 表达式会有所帮助:

Q(data) .then(data => getPromise1(globalVar) .then(re1a => getPromise2(JSON.parse(param2)

等等。没有嵌套和这种风格,它看起来不像回调地狱:)