I am trying to reuse the the data returned from promise here. But, the problem is, after the first call to checkPromise
function, it immediately calls the second function, and the promise for the first function is not fulfilled, so it never returns any data, and hence it never enters the if clause. How do I reuse a promise?
var Promise = require('bluebird');
var request = Promise.promisify(require("request"));
var url = 'http://www.google.com';
var obj = new Object;
function apiCall(url) {
return new Promise(function (resolve, reject) {
request(url).spread(function(response, body) {
return resolve(body);
}).catch(function(err) {
console.error(err);
return reject(err);
});
});
}
function checkPromise(url) {
if(obj.hasOwnProperty(url)) {
var rp = obj[url];
//do something
}
else {
apiCall(url).then(function(result) {
obj[url] = result;
//do something
});
}
}
checkPromise(url);
checkPromise(url);
No. It is not safe to resolve/reject promise multiple times. It is basically a bug, that is hard to catch, becasue it can be not always reproducible.
Promises have settled (hah) and it appears like it will never be possible to cancel a (pending) promise. Instead, there is a cross-platform (Node, Browsers etc) cancellation primitive as part of WHATWG (a standards body that also builds HTML) called AbortController .
You likely have a timing issue. Your apiCall()
function is asynchronous. That means it finishes sometime later. As such, each time you call checkPromise()
, all you're doing is starting a request and it finishes sometime later. So, you call it the first time and it starts a request (that has not finished yet). Then, your next call to checkPromise()
gets called and it does it's if
check before the first call has completed. Thus, it finds nothing in the cache yet.
Your code is running two requests in parallel, not one after the other.
If you actually want to wait until the first request is done before executing the second one, then you will have to actually structure your code to do that. You would need to make checkPromise()
return a promise itself so code using it could known when it was actually done in order to execute something after it was done.
FYI, I don't see anything in your code that is actually related to reusing promises (which is something you cannot do because they are one-shot objects).
Here's one possible implementation:
var Promise = require('bluebird');
var request = Promise.promisify(require("request"));
var url = 'http://www.google.com';
var obj = {};
function apiCall(url) {
return request(url).spread(function(response, body) {
return body;
});
}
function checkPromise(url) {
if(obj.hasOwnProperty(url)) {
var rp = obj[url];
//do something
return Promise.resolve(rp);
}
else {
return apiCall(url).then(function(result) {
obj[url] = result;
//do something
return result;
});
}
}
checkPromise(url).then(function() {
checkPromise(url);
});
Significant changes:
request()
rather than create yet another one.checkPromise()
so it always returns a promise whether the value is found in the cache or not so calling code can always work consistently.checkPromise()
calls so the first can finish before the second is executed.A very different approach would be to actually wait on the cache if a result you are interested in is already being loaded. That could be done like this:
var Promise = require('bluebird');
var request = Promise.promisify(require("request"));
var url = 'http://www.google.com';
var obj = {};
function apiCall(url) {
return request(url).spread(function(response, body) {
return body;
});
}
function checkPromise(url) {
if(obj.hasOwnProperty(url)) {
// If it's a promise object in the cache, then loading
// If it's a value, then the value is already available
// Either way, we wrap it in a promise and return that
return Promise.resolve(obj[url]);
} else {
var p = apiCall(url).then(function(result) {
obj[url] = result;
//do something
return result;
});
obj[url] = p;
return p;
}
}
checkPromise(url).then(function(result) {
// use result
});
checkPromise(url).then(function(result) {
// use result
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With