简体   繁体   English

如何在q中的承诺链的最后执行代码

[英]How to execute code at the very end of a promise chain in q

Let's say you have: 假设您有:

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

and then you have something like: 然后您会看到类似:

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);

Is there a way to modify foo so that afterItAll is executed after the after foo block? 有没有一种方法可以修改foo,以便在after foo之后执行afterItAll eg something like: 例如:

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');
});

The reason I ask is that I am developing an API where the user will make several of these foo calls and it would greatly cut down on the user's code if the after foo code was automatically executed after these API calls. 我问的原因是我正在开发一个API,用户将在其中进行几个此类foo调用,并且如果在这些API调用之后自动执行after foo代码,它将大大减少用户的代码。 I know I can use a callback to accomplish this, but I'd really like to stick with just using promises. 我知道我可以使用回调来完成此操作,但是我真的很想坚持使用诺言。

No, there is none. 不,没有。

Well, let's see what you're asking here: 好吧,让我们在这里看到您的要求:

Is there a way to modify foo so that afterItAll is executed after the after foo block? 有没有一种方法可以修改foo,以便在after foo块之后执行afterItAll?

This is effectively asking: 这实际上是在问:

Is there any way to know when no more .then handlers will be added to a specific promise? 有什么方法可以知道何时不再将.then处理程序添加到特定的Promise吗?

Which, given an arbitrary function we can decide to add a fooResult.then(function(){}) as the very last thing in the program before we return from it, so it's like asking: 其中,给定任意函数我们可以决定添加fooResult.then(function(){})如在程序中的最后一件事之前,我们return的,因此它就像问:

Is there any way to know when/if a function will return? 有什么方法可以知道何时/是否会返回一个函数吗?

Which, given a whole program as a function, is like asking: 给定整个程序的功能,就像问:

Is there any way to know if a program will ever halt? 有没有办法知道程序是否会停止?

It's not an easy thing to do to say the least. 至少要说不是一件容易的事 Not only is this feature non existent, it is theoretically impossible. 不仅不存在此功能,而且从理论上讲也是不可能的。

So how do I deal with it? 那么我该如何处理呢?

Bergi's answer gives you a pretty good idea. Bergi的答案为您提供了一个不错的主意。 The core here, that we fought for in Bluebird is nesting. 我们在Bluebird中争取的核心是嵌套。

Because we want something that's impossible in the general case we have to invert control, like callbacks do: 因为我们想要在一般情况下是不可能的事情,所以我们必须像回调一样反转控制:

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!");
    })
}

This would let you do: 这可以让您做到:

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

Which would run the setTimeoutPromise and then the more and then the other more and will log "after it all" after both are done. 哪个将运行setTimeoutPromise,然后运行more ,然后运行另一个,并且在两个都完成之后将“全部记录”。 This pattern is very useful for DB drivers and resource acquisition. 此模式对于数据库驱动程序和资源获取非常有用。

No, there is no such promise construct. 不,没有这样的诺言构造。 A promise does not - can not - know whether it is the end of a chain, or whether some other code will attach another link to it. 一个诺言不能-不能-知道它是一条链的末端,还是其他代码是否将另一个链接附加到它。

There is however nothing wrong with combining promises and callback code: 但是,将promise和回调代码组合在一起并没有错:

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

I'm not sure what your actual use case is here, but you also might want to have a look at Bluebird's Promise.using resource management pattern. 我不确定您的实际用例是什么,但是您可能还想看看Bluebird的Promise.using资源管理模式。

OK! 好! I hope my experience helps you. 希望我的经验对您有所帮助。

I had very similar problem. 我有非常类似的问题。

I wanted mysql connection pool to be released after all sql statement executed, or failed... like below 我希望在执行所有sql语句后释放mysql连接池,否则会失败...如下所示

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

This can be done .done() method like this 这样可以完成.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) My application Environment is node.js and using 'q' promise module PS)我的应用程序环境是node.js并使用'q'promise模块

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM