如何在q中的promise链的最末端执行代码

时间:2014-09-22 13:46:24

标签: javascript promise q chaining

我们说你有:

function setTimeoutPromise(ms) {
  var defer = Q.defer();
  setTimeout(defer.resolve, ms);
  return defer.promise;
}

然后你有类似的东西:

function foo(ms) {
  return setTimeoutPromise(ms).then(function () {
    console.log('foo');
  });
}

function afterItAll() {
  console.log('after it all');
}

foo(100).then(function () {
  console.log('after foo');
}).then(afterItAll);

有没有办法修改 foo ,以便在之后的 块之后执行 afterItAll ?例如类似的东西:

function foo(ms) {
  return setTimeoutPromise(ms).then(function () {
    console.log('foo');
  }).SOMEPROMISECONSTRUCT(function () {
    console.log('after it all');
  });
}

foo(100).then(function () {
  console.log('after foo');
});

我问的原因是我正在开发一个API,其中用户将进行其中几个 foo 调用,如果,它会大大减少用户的代码在这些API调用之后自动执行foo 代码之后。我知道我可以使用回调来实现这一点,但我真的很想坚持使用promises。

3 个答案:

答案 0 :(得分:3)

不,没有。

好吧,让我们看看你在这里问的是什么:

  

有没有办法修改foo,以便在After foo 块之后执行afterItAll?

这实际上是在问:

  

有没有办法知道什么时候不再有.then个处理程序添加到特定的承诺中?

在给定任意函数的情况下,我们可以决定在fooResult.then(function(){})之前添加return作为程序中的最后一项,所以它就像问:

  

有没有办法知道函数何时返回?

在整个程序作为一个函数的情况下,就像问:

  

有没有办法知道程序是否会停止?

It's not an easy thing to do至少可以说。这个特征不仅不存在,理论上也是不可能的。

那我该怎么处理呢?

Bergi's answer为您提供了一个非常好的主意。我们在Bluebird中为之奋斗的核心是嵌套。

因为我们想要的东西在一般情况下是不可能的,我们必须反转控制,就像回调一样:

function transaction(fn){
    // Promise.resolve().then( in ES6/Bluebird promises
    return Q().then(function(){ 
        return fn()
    }).finally(function(){ // same in Bluebird, in ES6 that's `.then(fn, fn)`
        console.log("after it all!");
    })
}

这可以让你这样做:

transaction(function(){
    return setTimeoutPromise().then(more).then(more);
});

哪个会运行setTimeoutPromise然后运行more然后运行另一个并且将记录"之后全部"两个完成后。此模式对于DB驱动程序和资源获取非常有用。

答案 1 :(得分:1)

不,没有这样的承诺构造。承诺不会 - 不能 - 知道它是否是链的末尾,或者某些其他代码是否会附加另一个链接。

组合promises和回调代码没有错:

function foo(ms, within) {
  return setTimeoutPromise(ms).then(function () {
    console.log('foo');
  })
  .then(within)
  .then(function afterFooAll() { // possibly use `finally` here?
    console.log('cleanup');
  });
}

foo(100, function () {
  console.log('inside foo');
}) // now returns a promise for cleanup been done

我不确定您的实际用例是什么,但您也可能希望查看Bluebird's Promise.using资源管理模式。

答案 2 :(得分:0)

OK!我希望我的经验对你有帮助。

我有类似的问题。

我希望在执行所有sql语句后释放mysql连接池, 或失败......如下所示

getConnection
.then(exeuteSQL('select ...'))
.then(exeuteSQL('select ...'))
.then(null, function(err){ //err handling })
....
.. finally execute pool release

这可以像这样完成.done()方法

getConnection
.then(exeuteSQL('select ...'))
.then(exeuteSQL('select ...'))
.then(null, function(err){ //err handling })
....
.done(function(){
    console.log('this line always executed!');
    req.conn.release();   // assuming connection attached to request object before
})

PS)我的应用程序环境是node.js并使用'q'promise模块