Simply save them inside of a closure.
var makePromise = function () {
var resolvePromise = null,
rejectPromise = null,
promise = new Promise(function (resolve, reject) {
resolvePromise = resolve;
rejectPromise = reject;
});
return { promise : promise, resolve : resolvePromise, reject : rejectPromise };
};
var deferredSomething = function () {
var deferredThing = makePromise();
waitAWhile()
.then(doStuff)
.then(function (result) {
if (result.isGood) {
deferredThing.resolve(result.data);
} else {
deferredThing.reject(result.error);
}
});
return deferredThing.promise;
};
This is actually the majority of the difference between the "deferred" concept and the "promise" concept; one more level, on top, that has the actual remote-controls that you can give to someone else, while you hand the .then|.success|.done|etc...
to your consumers.
Once you bring those functions out into your upstream process, you can happily lazy-load whatever you'd like, using the "thenable" which you'll return, and then succeed or fail your chain (or leave it hanging) at will...
UPDATE
Seeing as this is probably going to continue to be the chosen answer, and continue to be voted down, as the solution to the exact problem he was having (ie: retrofitting code which was not made with ES6 promises in mind), I figure I'll add a more detailed example of exactly why using this antipattern selectively can be better than naught:
MongoClient.connect("mongodb://localhost:21017/mydb", (err, db) => {
db.collection("mycollection", (err, collection) => {
collection.find().toArray((err, results) => {
doStuff(results);
});
});
});
If I were to write a library, here, hoping to reach the point where I could write:
let dbConnected = MongoClient.connect(dbURL);
dbConnected
.then(db => db.collection(myCollection))
.then(collection => collection.find(query))
.then(stream => doStuff(stream));
...or alternatively:
composeAsync(
(stream) => doStuff(stream),
(collection) => collection.find(query),
(db) => dbCollection(myCollection)
)(dbConnected);
...for ease of use within the library, does it make sense to wrap every single function-body within an instantiated promise
// find = curry(query, collection)
return new Promise(resolve, reject) {
/* whole function body, here /
/ do lots of stuff which is irrelevant to the resolution of mongo.db.collection.find, but is relevant to its calling */
collection.find(query).toArray( /node-callback/(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
};
...or in looking at the pattern of really only requiring the node-specific callback to be resolved, does it make more sense to have some form of promise-resolver, to save having to write out / copy-paste a half-dozen purely-redundant lines which should be completely DRYed up?
// find = curry(query, collection)
let resolver = new NodeResolver();
collection.find(query).toArray(promise.resolve);
return resolver.promise;
Yes, that is an anti-pattern... ...yet, an antipattern which requires fewer keystrokes, restores the natural flow of the promise-chain, fixes a problem with Node's callback-only API, reduces the potential for errors, et cetera.
Yes, there are already libraries which do this...
...solutions specific to X library or Y...
...or solutions which globally override methods of various modules (scary)
...or solutions which, again, basically force you to pass in all of the details of the call you're making:
wrapNodeMethod(fs, "read", url, config).then(data => { /*...*/ });
But there is no simple solution for the case of inverting all of that pain, without either:
a) wrapping the entire function body in a promise, to feed the async callback a resolver
b) using an antipattern within a library, in order to pass Node callbacks a resolver that the rest of the function-body needs to know precisely nothing about.
Even if data needed to be transformed within the resolver, it would still make more sense to return a transformed set, in a new promise
let resolver = new NodeResolver();
somethingAsync(resolver.resolve);
return resolver.promise.then(transformData).then(logTransform);
...than to wrap the whole body, including transforms, etc, just for closure-scope reference, just for the sake of avoiding an "antipattern" which clearly goes against the grain of what has become a very prominent JS platform/paradigm.
Now, personally, I'd be happier if IO||Node methods returned a promise and/or a stream, as well as taking a callback, as a core part of the platform...
...that's not going to happen...
...but you can't possibly tell me that writing less, and keeping Node modules DRY, while still using ES6 Promises is an "antipattern", without providing me a more-eloquent solution, therefore.
If you can, indeed, provide me something that I can use in any NodeJS callback, which does, indeed, provide a more eloquent solution to this, such that I don't have to wrap every body of every method which contains an async callback in a new constructor, or use clunky dispatcher methods, or hijack entire modules to override their global functionality...
...I'd be more than willing to retract my statement that this particular pattern is still highly-useful, as regards interfacing with APIs which are prone to pyramids o'dewm.
$(function() {}
in jQuery is an anti-pattern, since I'm asking for the same functionality except instead of being only a single event (dom ready), it can be based on ad-hoc events: Register functions to be called on an event, if functions are registered after the event is called, they will be called immediately with the same arguments. If you can figure out some way to do that without the "anti-pattern" then please share it. Simply saying "you don't really need that" doesn't help anyone and is like saying we don't really needDOM ready
. – Larimor