Resolve Javascript Promise outside function scope
simple:
var promiseResolve, promiseReject;
var promise = new Promise(function(resolve, reject){
promiseResolve = resolve;
promiseReject = reject;
});
promiseResolve();
Bit late to the party here, but another way to do it would be to use a Deferred object. You essentially have the same amount of boilerplate, but it's handy if you want to pass them around and possibly resolve outside of their definition.
Naive Implementation:
class Deferred {
constructor() {
this.promise = new Promise((resolve, reject)=> {
this.reject = reject
this.resolve = resolve
})
}
}
function asyncAction() {
var dfd = new Deferred()
setTimeout(()=> {
dfd.resolve(42)
}, 500)
return dfd.promise
}
asyncAction().then(result => {
console.log(result) // 42
})
ES5 Version:
function Deferred() {
var self = this;
this.promise = new Promise(function(resolve, reject) {
self.reject = reject
self.resolve = resolve
})
}
function asyncAction() {
var dfd = new Deferred()
setTimeout(function() {
dfd.resolve(42)
}, 500)
return dfd.promise
}
asyncAction().then(function(result) {
console.log(result) // 42
})
No, there is no other way to do this - the only thing I can say is that this use case isn't very common. Like Felix said in the comment - what you do will consistently work.
It's worth mentioning that the reason the promise constructor behaves this way is throw safety - if an exception you did not anticipate happens while your code is running inside the promise constructor it will turn into a rejection, this form of throw safety - converting thrown errors to rejections is important and helps maintain predictable code.
For this throw safety reason, the promise constructor was chosen over deferreds (which are an alternative promise construction way that do allow what you're doing) - as for best practices - I'd pass the element and use the promise constructor instead:
var p = new Promise(function(resolve, reject){
this.onclick = resolve;
}.bind(this));
For this reason - whenever you can use the promise constructor over exporting the functions - I recommend you do use it. Whenever you can avoid both - avoid both and chain.
Note, that you should never use the promise constructor for things like if(condition)
, the first example could be written as:
var p = Promise[(someCondition)?"resolve":"reject"]();
I liked @JonJaques answer but I wanted to take it a step further.
If you bind then
and catch
then the Deferred
object, then it fully implements the Promise
API and you can treat it as promise and await
it and such.
⚠️ Editor's Note: I don't recommend this kind of pattern anymore since at the time of writing,
Promise.prototype.finally
was not a thing yet, then it became a thing… This could happen to other methods so I recommend you augment the promise instance withresolve
andreject
functions instead:function createDeferredPromise() { let resolve let reject const promise = new Promise((thisResolve, thisReject) => { resolve = thisResolve reject = thisReject }) return Object.assign(promise, {resolve, reject}) }
Go upvote someone else's answer.
class DeferredPromise {
constructor() {
this._promise = new Promise((resolve, reject) => {
// assign the resolve and reject functions to `this`
// making them usable on the class instance
this.resolve = resolve;
this.reject = reject;
});
// bind `then` and `catch` to implement the same interface as Promise
this.then = this._promise.then.bind(this._promise);
this.catch = this._promise.catch.bind(this._promise);
this.finally = this._promise.finally.bind(this._promise);
this[Symbol.toStringTag] = 'Promise';
}
}
const deferred = new DeferredPromise();
console.log('waiting 2 seconds...');
setTimeout(() => {
deferred.resolve('whoa!');
}, 2000);
async function someAsyncFunction() {
const value = await deferred;
console.log(value);
}
someAsyncFunction();
A solution I came up with in 2015 for my framework. I called this type of promises Task
function createPromise(handler){
var resolve, reject;
var promise = new Promise(function(_resolve, _reject){
resolve = _resolve;
reject = _reject;
if(handler) handler(resolve, reject);
})
promise.resolve = resolve;
promise.reject = reject;
return promise;
}
// create
var promise = createPromise()
promise.then(function(data){ alert(data) })
// resolve from outside
promise.resolve(200)