5

I'm using Babel for a project, and I'm stuck with a very basic problem. I'm very used to jQuery's Deferred objects and I'm struggling to find its ES2015 equivalent, here is what I basically want:

// file1.js
let dfd = new Promise()

function functionCalledAtSomePoint(thing) {
    dfd.resolve(thing)
}

export default { dfd }


// file2.js
import { dfd } from './file1'

dfd.then((thing) => {
    console.log('Yay thing:', thing)
})

What should be the correct way to write this simple deferred?

EDIT with royhowie's answer:

// file1.js
let thing
function getThing(_thing) {
    return new Promise((resolve) => {
        if (el) {
            thing = new Thing(el)
        }
        resolve(thing)
    })
}

function functionCalledAtSomePoint(el) {
    getThing(el)
}

export default { getThing }


// file2.js
import { getThing } from './file1'

getThing.then((thing) => {
    console.log('Yay thing:', thing)
})
trincot
  • 317,000
  • 35
  • 244
  • 286
Calvein
  • 2,111
  • 13
  • 28
  • babel has an informative "getting started" guide, which talks about promises in es6: https://babeljs.io/docs/learn-es2015/#promises – royhowie Jul 11 '15 at 06:43
  • I read it first, then MDN, then things on Google and I still can't get my head around it :/ – Calvein Jul 11 '15 at 06:45
  • possible duplicate of [How do I convert an existing callback API to promises?](http://stackoverflow.com/q/22519784/1048572) – Bergi Jul 12 '15 at 13:02

3 Answers3

5

You can export the promise directly (instead of a function)—like you have—but then you'll only be able to use it (.then) once, which is probably not what you want.

Instead, you should export a function which returns a Promise:

file 1.js

import User from '../models/user'

export function getUsersFromDatabase () {
    return new Promise((resolve, reject) => {
        User.find({}, (err, users) => {
            return err ? reject(err) : resolve(users)
        })
    })
}

file2.js

import { getUsersFromDatabase } from './file1'

getUsersFromDatabase().then((users) => {
    // success
}).catch((err) => {
    // no users
})

You can use the default Promise implementation, but it much slower than 3rd party modules, e.g., bluebird (which I very much recommend using).

royhowie
  • 11,075
  • 14
  • 50
  • 67
  • @JaromandaX then he can use the default implementation (which is currently very slow). bluebird is Promise/A+ standard compliant, so it should work as a drop-in replacement. – royhowie Jul 11 '15 at 06:55
  • @zerkms I can't find the exact page I'm after, but https://github.com/petkaantonov/bluebird/tree/master/benchmark is telling. Note how the native implementation is an order of magnitude slower (389 v. 3532). – royhowie Jul 11 '15 at 06:59
5

I'm very used to jQuery's Deferred objects and I'm struggling to find its ES2015 equivalent

If you must use deferred, this should work

function makeDeferred() {
    var res, rej;
    let dfd = new Promise(function(resolve, reject) {
        res = resolve;
        rej = reject;
    });
    dfd.resolve = res;
    dfd.reject = rej;
    return dfd;
}
let dfd = makeDeferred();

However, rewriting your code to avoid such kludge would be preferable (but not unavoidable - I still have one piece of code I can't get rid of the deferred promise in, so I feel your pain

Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
0

This class will allow you to use the regular Promise methods as well as an additional resolve(value) method. This should give you a similar functionality as jQuery.deferred().

function DeferredPromise() {
    var _resolve = null;
    var _reject = null;

    this.promise = new Promise(function(resolve, reject) {
        _resolve = resolve;
        _reject = reject;
    });
    this.then = function() {
        return this.promise.then(...arguments);
    }
    this.catch = function() {
        return this.promise.catch(...arguments);
    }
    this.resolve = function() {
        _resolve(...arguments);
    }
    this.reject = function() {
        _reject(...arguments);
    }
}

Then you can use it to create a new DeferredPromise:

var p = new DeferredPromise();

Wait for it:

p.then(val => {
    console.log('val(1)', val);
})

Maybe wait for it another time, you can also chain it with a regular Promise:

p.then(val => {
    console.log('val(2)', val);
    return 42;
 }).then(val => {
    console.log('.then(somethingElse)', val);
 })
 .catch(err => { console.error('err', err); })

And resolve it whenever you want:

p.resolve({ username: 'Luke.Skywalker', age: 42 });
Micha Mazaheri
  • 3,481
  • 1
  • 21
  • 26