【问题标题】:Call a Q promise function after promise chain invoked调用承诺链后调用 Q 承诺函数
【发布时间】:2017-08-12 04:01:33
【问题描述】:

我正在使用 Q Promise 库在 Node.js 应用程序中工作。我有两组承诺链,一组用于控制流程,另一组用于调用我从中检索数据的服务方法,我的问题是,我需要将承诺链的返回值获取到我的另一个承诺链。

MyExample.js

bookService.getBookById(bookId)
  .then(bookDetals)
  .then(function(returnValue) { // <- (A)
    res.send(200, returnValue); // <- (C)
    return returnValue;
  }).catch(function(error) {
    logger.error('Error getting values');
    res.send(500, error);
  });


bookDetals = function(book) {
  myService.retrieveATypeData(book, bookId)
    .then(function(bookData) {
      myService.retrieveBTypeData(bookId)
        .then(function(bdata) {
          bookData[bTypeData] = bdata;
          myService.retrieveCTypeData(bookId)
            .then(function(cdata) {
              bookData[cTypeData] = cdata;
            }).done(function() {
              return bookData; // <- (B)
            })
        });
    });
};

在上面的代码中,我调用了 bookService.getBookById(bookId) 并获取了这本书。然后我调用 bookDetals 函数,它是一个承诺链。但我的问题是它在承诺链结束之前返回 returnValue 。如何让 Promise 链的返回值(在 (B) 行)返回原地 (C)。目前它之前返回。所以在地方 C 它说未定义。

【问题讨论】:

  • 您的 bookDetals 函数(以及其中的所有回调函数)缺少 return 语句 - 如果不返回承诺,then 怎么能等待它?!
  • 哦,不要使用done - 你只需要then

标签: javascript node.js promise q


【解决方案1】:

由于您使用的是 Node,我将转向 ES6 Promises。如果您当前的版本还不支持 ES6 Promises,我建议您切换到为您填充它的库 (es6-promise)。使用 ES6,你可以这样做:

// mock async promise
const getThing = id => (
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        id
      });
    }, 250);
  })
);

// mock async promise
const getDetailsA = thing => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Object.assign({}, thing, {
        a: 'purple'
      }));
    }, 250);
  })
};

// mock async promise
const getDetailsB = thing => (
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Object.assign({}, thing, {
        b: 'monkey'
      }));
    }, 250);
  })
);

// mock async promise
const getDetailsC = thing => (
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Object.assign({}, thing, {
        c: 'dishwasher'
      }));
    }, 250);
  })
);

getThing('123')
  .then(getDetailsA)
  .then(getDetailsB)
  .then(getDetailsC)
  .then(console.log)
  .catch(console.error);

【讨论】:

  • @BenjaminGruenbaum 也许你错过了我代码中的 cmets。我编写的函数只是为了“模拟”一个返回承诺的 API,这不被视为反模式。这些功能的实现是合理的,也不被视为反模式。
  • @BenjaminGruenbaum 如果您能删除反对票,那就太好了。
  • const timeout = ms =&gt; new Promise(r =&gt; setTimeout(r, ms)) 会将你所有的函数变成const getDetailsC =&gt; thing =&gt; timeout(ms).then(() =&gt; ({...thing, c: 'dishwasher')) 等等。
  • 如果我关心优化我的模拟代码,那就太好了。同样,您错过了我的回答的重点。您关注的是我的模拟,而不是承诺的链接,这是问题的实际答案。
【解决方案2】:

你需要返回一个promise:

bookDetals = function(book) {
  return Q.Promise(function(resolve, reject, notify) {
    myService.retrieveATypeData(book, bookId)
        .then(function(bookData) {
          myService.retrieveBTypeData(bookId)
            .then(function(bdata) {
              bookData[bTypeData] = bdata;
              myService.retrieveCTypeData(bookId)
                .then(function(cdata) {
                  bookData[cTypeData] = cdata;
                }).done(function() {
                  resolve(bookData); // <- (B)
                })
            });
        });
  }  
}


编辑

deferredhere 讨论的反模式。老实说,最好使用 polyfill,因为 Promise 在 es6 规范中。

【讨论】:

猜你喜欢
  • 2015-04-15
  • 1970-01-01
  • 1970-01-01
  • 2018-07-06
  • 1970-01-01
  • 2022-01-08
  • 2017-03-26
  • 2015-05-12
  • 2017-03-31
相关资源
最近更新 更多