Возможно, у вас есть проблема с синхронизацией. Ваша функция apiCall()
является асинхронной. Это означает, что он закончится когда-нибудь позже. Таким образом, каждый раз, когда вы вызываете checkPromise()
, все, что вы делаете, это запуск запроса, и он заканчивается через некоторое время. Итак, вы называете это в первый раз и запускаете запрос (который еще не закончен). Затем вызывается ваш следующий вызов checkPromise()
, и он делает это if
до того, как завершится первый звонок. Таким образом, он еще ничего не обнаружил в кеше.
Ваш код выполняет два запроса параллельно, а не один за другим.
Если вы действительно хотите дождаться, пока первый запрос не будет выполнен до выполнения второго, вы должны будете на самом деле структурировать свой код для этого. Вам нужно будет сделать checkPromise()
, чтобы вернуть обещание, поэтому код, использующий его, мог бы быть известен, когда он был фактически выполнен, чтобы выполнить что-то после его завершения.
FYI, я ничего не вижу в вашем коде, что на самом деле связано с повторным использованием обещаний (чего вы не можете сделать, потому что это объекты с одним выстрелом).
Вот одна из возможных реализаций:
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);
});
Существенные изменения:
- Возвращение обещание возвращаемый
request()
, а не создавать еще один один.
- Измените
checkPromise()
, чтобы он всегда возвращал обещание, находится ли значение в кеше или нет, поэтому код вызова всегда может работать последовательно.
- Последовательность двух вызовов
checkPromise()
, поэтому первая может закончиться до выполнения второго.
Совсем иной подход был бы на самом деле ждать кэша, если результат вас интересует уже загружен. Это может быть сделано так:
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
});
Почему вы не храните результаты в закрытии? –
Обетование нельзя «повторно использовать». Он успешно (один раз), или он терпит неудачу (один раз), или не сделал этого. Это на самом деле очень хорошо. Используйте вторичный механизм для хранения данных. В любом случае обещание будет использоваться .. не асинхронно (т. Е. Обещание еще не завершено еще во втором вызове), что противоречит фундаментальному характеру обещания. (Как правило, плохо сделать функцию «возможно, асинхронно», поскольку она [выпускает Zalgo] (http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony)). – user2864740