How do you return promises from functions that don

2019-02-19 17:45发布

问题:

I asked Is wrapping a promise in a promise an anti-pattern? a few days ago which led me to this.

In that case I had to deal with a setTimeout, which doesn't allow for return values. Thankfully you can deal with this by using the built in delay function (at least for bluebird promises).

But what about for something like a gulp task? Also inspired by another question: How to pass an object from gulpfile to another JavaScript file in nodejs?

var stuff;
gulp.task('LoadYamlFiles', function() {
  // do stuff
  stuff = 'blah';
});

module.exports = { stuff };

The export wouldn't be 'blah' because the gulp task runs asynchronously. This can be solved using promises.

One way you could do it is using a deferred (code from https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns):

// setTimeout that returns a promise
function delay(ms) {
    var deferred = Promise.pending();
    setTimeout(function(){
        deferred.resolve();
    }, ms);
    return deferred.promise;
}

And this actually isn't considered an anti-pattern according to their wiki, but I see the usage of deferred discouraged a lot. This seems important to acknowledge because bluebird doesn't even have the .pending() method in their API anymore, meaning I can't really do it this way even if I wanted to.

However you can't do:

var stuff;
var myPromise = gulp.task('LoadYamlFiles', function() {
  return new Promise(function(resolve, reject) {
    // do stuff
    stuff = 'blah';
    resolve(stuff);
  })
});

module.exports = { myPromise };

because the return value of the anonymous function isn't what myPromise will contain. Also it would cause the problems you can see here Does a gulp task have to return anything?

So how do you deal with these cases where normally you would use the de facto deprecated deferred pattern?

回答1:

You named your variable myPromise, that's a first hint that whatever is on the other side of the =, it should be a promise. So let's start with

var myPromise = new Promise((resolve, reject) => {
  // todo
});

module.exports { myPromise };

Now, let's fill in the details.

var myPromise = new Promise((resolve, reject) => {
  gulp.task('LoadYamlFiles', function() {
    let stuff = 'blah';
    resolve(stuff);
  });
});

A bit of refactoring gives us

let myPromise = new Promise(resolve => 
  gulp.task('LoadYamlFiles', () => resolve('blah')));

I'm sure this isn't a real usecase, but it can apply nonetheless.

Also see:

  • How do I convert an existing callback API to promises?
  • How do I return the response from an asynchronous call?