How to resolve or reject a (native) JavaScript Promise out of its scope?

Question:

Most of the implementations I see of Promises (promises) in JavaScript frameworks handle the use of Promises so that you can access the functions responsible for rejection and resolution at any scope.

For example, Angular:

var defer = $q();

setTimeout(function () {
    defer.resolve({status: true});
}, 5000);

defer.promise.then(function (data) {
    console.log(data.status);
});

Something similar is possible to do in jQuery.

However, when using JavaScript's native Promise , I can't see how I could do such an operation, unless the call is inside the callback passed as an argument.

To do it in Javascript, I would theoretically have to do it like this:

 var p = new Promise(function (reject, resolve) {
        setTimeout(() => p({status: true}, 5000);
  });

  p.then((data) => console.log(data.status));

My question is whether there is any way to do the same operation, using JavaScript's native Promise , as I did in the first example. Because, depending on the structure of the project, it could be horrible having to be held hostage to encapsulating something inside a callback to have Promise functionality. And from what I've been researching on the internet, it seems that Javascript Promise was made to be used anyway. :\

Is there any simple way to get around this limitation of JavaScript's implementation of promises?

Note: I tried using the Promise.resolve(promise) , but I didn't get the desired effect.

Answer:

You could do this kind of workaround:

const controls = {};
const promise = new Promise((resolve, reject) => {
  controls.resolve = resolve;
  controls.reject = reject;
});

promise.then((val) => {
  console.log('Fui resolvida. Valor de resolução:', val);
});

setTimeout(() => {
  controls.resolve(1);
}, 1000);

This type of code is possible since the executor function (first argument passed to the Promise constructor) is executed synchronously, which allows you to "pull out" the resolve and reject functions from within the callback .

However, the code above can be considered an anti-pattern (so much so that I hid it by default) and therefore its use should be discouraged. By design, Promise s were architected to be resolved only through the functions ( resolve and reject ) passed to the executor. As such, it is not so much a "limitation" as a choice.

The Promise constructor behaves this way for a reason called throw safety . This means that if an exception is thrown from within the executor, the Promise constructor itself will catch the error and immediately reject the Promise , being the rejection value of the error itself thrown. This is important as it maintains predictable code. [Reference]

Therefore, when there is a need to resolve a "promise" from outside its executor, it is better to use a deffered , which allows you to do this. JavaScript Promise was not made with this use-case in mind. jQuery, for example, implements jQuery.Deferred . It is worth noting that promises and deferreds , although they have similar functions, are not the same thing.


It is worth noting that the ("static") method Promise.resolve is not used to resolve a Promise , but rather to create a new promise, which will immediately resolve with the value passed as the first argument of Promise.resolve . There is also the Promise.reject method, which behaves the same way to create an immediately rejected promise.

That's not the case, but if there were a Promise.prototype.resolve method, it would be used to resolve existing Promise instances .

Scroll to Top