Resolving ES6 promises from outside

Resolving ES6 promises from outside

16 Feb 2020 async es6 promises javascript

There's no quesiton that the Promises API, introduced in ES6, has helped greatly in designing the chronology and dependencies side of scripts.

But I've always found it a little odd that the API was designed such that you have to resolve the promises from inside the callback like so:

let prom = new Promise(resolve => { resolve(); }); prom.then(() => alert('done'));

My issue with that is I don't like being forced into closures where it doesn't seem necessary. The jQuery Deferred Objects API seems more elgant (purely in my opinion). No forced closure, and you can resolve from outside, like so:

let dfd = new Deferred; dfd.resolve(); dfd.done(() => alert('done'));

This is just my preference (and the preference of many others). The spec writers obviously took the decision to not go the Deferred model route.

Because of this it's quite commonly asked whether the jQuery pattern can be used with ES6 Promises, and the answer is it can.

Doing so involves giving your resolve callback lexical scope outside its immediate closure. We can do this by declaring the variable outside it, then assigning to it the value of the callback.

let res; //placeholder for resolver callback, outside of promise let prom = new Promise(inner_res => { res = inner_res; //assign resolver callback as value to outside @res }); prom.then(() => alert('done')); setTimeout(res, 1000);

The only slightly ugly thing here is we create two variables rather than one. Nicer would be, again like Deferreds, if we could put the resolver callback onto the Promise as a method. We could do that with a "Promise creation factory", inspired by this SO answer.

function promiseCreator() { let res, prom = new Promise(inner_res => { res = inner_res; }); prom.resolve = res; return prom; }

Our function returns a new Promise, with the resolver callback callable as a method of the Promise, like so:

let prom = promiseCreator(); prom.then(() => alert('done')); setTimeout(prom.resolve, 1000); //see here

I quite like that; Deferred-like behaviour, while at the same time writing only one scope variable (the Promise), not two (the Promise plus the resolver).