Promises were originally designed for asynchronous operations, but isGood()
is using them as a boolean. Instead of just resolving or rejecting with a boolean value, the state of the promise itself is being used to convey information:
- pending == unknown
- resolved == true
- rejected == false
While some may see this as unconventional use of promises, it can be fun to explore their capabilities in this way.
The main challenges with treating promises as booleans are:
- 'true' will follow the success path and 'false' will follow the fail path
- Promise libraries don't offer built-in support for boolean algebra operators like NOT, AND, OR, XOR
Until these aspects are further researched and documented, it requires creativity to leverage these features effectively.
Let's address this issue using jQuery, which I am more familiar with.
First, let's redefine isGood()
:
function isGood(number) {
return $.Deferred(function(dfrd) {
if(parseInt(number, 10) == number) {
setTimeout(function() { dfrd.resolve(number); }, 100);//"true"
} else {
setTimeout(function() { dfrd.reject(number); }, 100);//"false"
}
}).promise();
}
We need a method to reverse the state of a promise, since jQuery promises do not have a native inversion function. Here's how you can implement that:
function invertPromise(p) {
return $.Deferred(function(dfrd) {
p.then(dfrd.reject, dfrd.resolve);
});
}
Now, let's modify the findGoodNumber()
function to utilize the revamped isGood()
method and the invertPromise()
utility:
function findGoodNumber(numbers) {
if(numbers.length === 0) {
return $.Deferred.reject().promise();
} else {
return invertPromise(numbers.reduce(function(p, num) {
return p.then(function() {
return invertPromise(isGood(num));
});
}, $.when()));
}
}
You can then call the same routine with different data:
var arr = [3.1, 9.6, 17.0, 26.9, 89];
findGoodNumber(arr).then(function(goodNumber) {
console.log('Good number found: ' + goodNumber);
}, function() {
console.log('No good numbers found');
});
This demonstrates how promises can be manipulated to represent boolean values asynchronously.
Alternative Approach
A different approach to solving this problem without needing inversion is by performing an "OR-scan". This alternative solution using jQuery is:
function findGoodNumber(numbers) {
if(numbers.length === 0) {
return $.Deferred.reject().promise();
} else {
return numbers.reduce(function(p, num) {
return p.then(null, function() {
return isGood(num);
});
}, $.Deferred().reject());
}
}
This offers another way to handle the problem without requiring explicit inversions.