Я пытаюсь создать наблюдаемый поток, который удовлетворяет следующим требованиям:
- Загрузка данных из хранилища во время подписки
- Если данные еще не истекли, верните наблюдаемое значение
- Если данные истекли, верните HTTP-запрос, наблюдаемый, который использует токен обновления, чтобы получить новое значение и сохранить его
- Если этот код достигнут снова до завершения запроса, верните тот же запрос, который можно наблюдать
- Если этот код достигнут после завершения предыдущего запроса или с другим токеном обновления, запустите новый запрос
Я знаю, что есть много разных ответов о том, как выполнить шаг (3), но поскольку я пытаюсь выполнить эти шаги вместе, я ищу руководство относительно того, было ли решение, с которым я столкнулся, наиболее кратким это может быть (что я сомневаюсь!).
Здесь образец, демонстрирующий мой текущий подход:
var cachedRequestToken;
var cachedRequest;
function getOrUpdateValue() {
return loadFromStorage()
.flatMap(data => {
// data doesn't exist, shortcut out
if (!data || !data.refreshtoken)
return Rx.Observable.empty();
// data still valid, return the existing value
if (data.expires > new Date().getTime())
return Rx.Observable.return(data.value);
// if the refresh token is different or the previous request is
// complete, start a new request, otherwise return the cached request
if (!cachedRequest || cachedRequestToken !== data.refreshtoken) {
cachedRequestToken = data.refreshtoken;
var pretendHttpBody = {
value: Math.random(),
refreshToken: Math.random(),
expires: new Date().getTime() + (10 * 60 * 1000) // set by server, expires in ten minutes
};
cachedRequest = Rx.Observable.create(ob => {
// this would really be a http request that exchanges
// the one use refreshtoken for new data, then saves it
// to storage for later use before passing on the value
window.setTimeout(() => { // emulate slow response
saveToStorage(pretendHttpBody);
ob.next(pretendHttpBody.value);
ob.completed();
cachedRequest = null; // clear the request now we're complete
}, 2500);
});
}
return cachedRequest;
});
}
function loadFromStorage() {
return Rx.Observable.create(ob => {
var storedData = { // loading from storage goes here
value: 15, // wrapped in observable to delay loading until subscribed
refreshtoken: 63, // other process may have updated this between requests
expires: new Date().getTime() - (60 * 1000) // pretend to have already expired
};
ob.next(storedData);
ob.completed();
})
}
function saveToStorage(data) {
// save goes here
}
// first request
getOrUpdateValue().subscribe(function(v) { console.log('sub1: ' + v); });
// second request, can occur before or after first request finishes
window.setTimeout(
() => getOrUpdateValue().subscribe(function(v) { console.log('sub2: ' + v); }),
1500);