AFAIK Deferreds can only be resolved once
Correct. A promise that transitioned from pending state to fulfilled or rejected states (aka was resolved) can no longer change state. The promise specification says this explicitly:
When fulfilled/rejected, a promise must not transition to any other state.
So, there you have it, no - promises do not change states after being resolved. Just like a function that returned a value doesn't suddenly throw an exception in retrospect. Whenever you're unsure - think about the sync code analogy
var x = foo(); // returns correctly
// .. more code
You wouldn't expect foo
to throw after it returned or return after it threw just like you wouldn't expect a promise to reject after it resolved or resolve after it rejected.
Is there some way I can overwrite the deferred's value or if (as I suspect) it's inadvisable (even impossible) are there any tried and tested approaches to this problem? Here's some skeleton code to illustrate the problem
No, a promise is an abstration over a single computation. Settling it twice makes no sense. It seems like it is the wrong abstraction for your goal.
Promises are a great flow control mechanism but they're not intended to solve every problem asnychronosu code has to deal with. They are not event emitters for one.
This problem however can be solved with promises rather easily:
// articles module
var articles = {},
// anId = 'uuid';
articles.get = function(anId){
if(articles[anId]){
return $.when(articles[anId]); // return cached copy
}
return $.get('/articles/' + anId).then(function(article){
articles[anId] = article;
return article;
});
}
articles.refresh = function(anId){
return $.get('/articles/refresh/' + anId).then(function(article){
articles[anId] = article;
return article;
});
});
//another module
var localCopyOfArticle,
getArticle = function (anId) {
return localCopyOfArticle = articles.get(anId); // now a promise
}
// back to articles
// the .then here is __CRUCIAL__ since the refresh operation is async itself
articles.refresh(anId).then(function(article){
console.log(article); // fresh
return getArticle(anId)
}).then(function(article){
console.log(article); // from getArticle, also fresh!
});
This code has a lot of 'cruft' to illustrate the point. The important thing is to realize that the operations are a new operation each time. Fetching the data is a new operation each time and not the same one. Just like in synchronous code. Store the values in the map and not the promises and the fetch operation should be promise based.