2

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?

Community
  • 1
  • 1
m0meni
  • 16,006
  • 16
  • 82
  • 141
  • afaik, "deferred" is only "deprecated" as a specific thing in jQuery, not as a concept in general. that said, you can make a promise outside the callback and resolve it from inside the callback... – dandavis Jan 10 '16 at 21:09
  • I use `var wait = ms => new Promise(resolve => setTimeout(resolve, ms));`, and then avoid setTimeout everywhere else, because of its poor error handling characteristics. – jib Jan 11 '16 at 02:10

1 Answers1

4

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:

Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308
  • I agree with this, and actually I recall that I've done it a few times before. Out of curiosity is there a way to do it without wrapping the entire task in a promise? – m0meni Jan 10 '16 at 21:10
  • But that's exactly what a promise is. A promise is a proxy to a value, "I *promise* you that a value (or an error) will arrive sometime in the future". So you basically, need the promise wrapper. Normally, it's better to wrap the whole thing in a function and call it, allows you to pass parameters into the Promise constructor via closure. – Madara's Ghost Jan 10 '16 at 21:11
  • Would it be possible to do something like this: https://jsfiddle.net/zrg01t65/1/? Obviously the example doesn't actually work since fiddle doesn't have gulp, but is valid? – m0meni Jan 10 '16 at 21:17
  • No, where does your `resolve()` come from in the second function? Read the first question/answer I linked. – Madara's Ghost Jan 10 '16 at 21:18
  • Thanks for all your help today. I ended up taking my broken idea from above and making this: https://github.com/AriaFallah/pwrap. Not sure how useful it'll be if at all, but it was pretty nice being able to make my first module for npm. I appreciate you answering everything :D – m0meni Jan 11 '16 at 03:01
  • @AR7 If you're working server-side, I recommend that you use Bluebird (a promise library), it has awesome helper features, it's faster than native promises, and it can promisify callback functions (and even entire objects) – Madara's Ghost Jan 11 '16 at 07:38