Creating a (ES6) promise without starting to resolve it

人走茶凉 提交于 2019-11-28 16:57:54
Benjamin Gruenbaum

Good question!

The resolver passed to the promise constructor intentionally runs synchronous in order to support this use case:

var deferreds = [];
var p = new Promise(function(resolve, reject){
    deferreds.push({resolve: resolve, reject: reject});
});

Then, at some later point in time:

 deferreds[0].resolve("Hello"); // resolve the promise with "Hello"

The reason the promise constructor is given is that:

  • Typically (but not always) resolution logic is bound to the creation.
  • The promise constructor is throw safe and converts exceptions to rejections.

Sometimes it doesn't fit and for that it the resolver runs synchronously. Here is related reading on the topic.

I want to add my 2 cents here. Considering exactly the question "Creating a es6 Promise without starting resolve it" I solved it creating a wrapper function and calling the wrapper function instead. Code:

Let's say we have a function f which returns a Promise

/** @return Promise<any> */
function f(args) {
   return new Promise(....)
}

// calling f()
f('hello', 42).then((response) => { ... })

Now, I want to prepare a call to f('hello', 42) without actually solving it:

const task = () => f('hello', 42) // not calling it actually

// later
task().then((response) => { ... })

Hope this will help someone :)


Referencing Promise.all() as asked in the comments (and answered by @Joe Frambach), if I want to prepare a call to f1('super') & f2('rainbow'), 2 functions that return promises

const f1 = args => new Promise( ... )
const f2 = args => new Promise( ... )

const tasks = [
  () => f1('super'),
  () => f2('rainbow')
]

// later
Promise.all(tasks.map(t => t()))
  .then(resolvedValues => { ... })

How about a more comprehensive approach?

You could write a Constructor that returns a new Promise decorated with .resolve() and .reject() methods.

You would probably choose to name the constructor Deferred - a term with a lot of precedence in [the history of] javascript promises.

function Deferred(fn) {
    fn = fn || function(){};

    var resolve_, reject_;

    var promise = new Promise(function(resolve, reject) {
        resolve_ = resolve;
        reject_ = reject;
        fn(resolve, reject);
    });

    promise.resolve = function(val) {
        (val === undefined) ? resolve_() : resolve_(val);
        return promise;//for chainability
    }
    promise.reject = function(reason) {
        (reason === undefined) ? reject_() : reject_(reason);
        return promise;//for chainability
    }
    promise.promise = function() {
        return promise.then(); //to derive an undecorated promise (expensive but simple).
    }

    return promise;
}

By returning a decorated promsie rather than a plain object, all the promise's natural methods/properties remain available in addition to the decorations.

Also, by handling fn, the revealer pattern remains availble, should you need/choose to use it on a Deferred.

DEMO

Now, with the Deferred() utility in place, your code is virtually identical to the jQuery example.

var deferreds = {};
function waitFor(key: string): Promise<any> {
  if (key in promises) {
    return deferreds[key].promise();
  }
  var def = Deferred();    
  deferreds[key] = def;
  return def.promise();
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!