This document assumes you're using require('promise'), from:
https://github.com/then/promise
(this is what we use throughout taskcluster)
// All code paths here are valid
var asyncFunc = function() {
return new Promise(function(accept, reject) {
if (...) {
accept(...)
} else if (...) {
reject(new Error(...));
} else {
throw new Error(...);
}
});
};
// All code paths here are valid
var asyncFunc = function() {
return new Promise(function FNAME(accept, reject) {
setTimeout(function() {
if (...) {
accept(...)
} else if (...) {
reject(new Error(...));
} else {
reject(new Error(...));
}
}, 1000)
});
};
var p = asyncFunc()
p.then(function(val) {....})
// This is also valid, asyncFunc will be called twice, second time
// with result as argument
var asyncFunc2 = function() {
return asyncFunc().then(function(result) {
return asyncFunc3(result).then(function(result2) {
// if exception here...
return result === result2;
}).catch(function(err) {
return false;
});
}).then(function(yes) {
if (yes === true) {
return "YES";
} else {
return "NO!";
}
});
};
// This function always returns a promise, but sometimes the
// promise is resolved synchronously. Callers of this function
// won't know the difference, because it always returns a promise
var conditionalAsyncFunc = function() {
if (...) {
return asyncFunc2();
}
// In case we want to provide a promise that is already
// resolved
return Promise.resolve(null);
};
Questions?
No, that all makes sense. In my code, getPrivateVariable is async so I'm using the pattern as in 'asyncFunc' above.
jonasfj: But you function is async because and only because, it
calls other async functions that promise you with a promise.
So instead of using the 'asyncFunc' pattern, I suggest that
you use the 'asyncFunc2' pattern, which assumes a the async
methods used returns a promise.
It's a lot cleaner, and much harder to forget to resolve.
It's also known as promise chaining or something like that.
Note, the reason I showed you the conditionalAsync pattern is
because you have that too. where you call resolve(null), in the
else-flow.
russn: ok, that I understand, that in that flow it's sync and I can use Promise.resolve
jonasfj: Okay, link to the code? or continue :)
Formally:
let p be a promise, and q a function, then:
o = p.then(q)
We now say that:
q is a promise-handler
And we have that:
o is a promise that p happened followed by the promise-handler q
Hence, if q returns a promise, then o is not resolved before
that promise is resolved.
russn: I have my gaia standup now, I'll review this and let you know in a few minutes what other questions I have. Thanks.
jonasfj: okay...
btw, I have contributor who also finds this hard to understand. Would love if we could come up with a great and quick way to explain it.
Promises are powerful and simple when you get them, but it's not intuitive (though they do the right thing most of the time).
russn: I think I'm most of the way there but some dots are not connected...
garndt: if you find a way of explaining this that's less painful, please loop me in because I feel I just bang on the keyboard until promises work rather than truly understanding them.
-----------------------------------------------------------------
More questions any one?