A promise is a one-way latch. Once it is resolved with a value or rejected with a reason, its state and value/reason can never change. So, no matter how many times you do .then()
on the same promise, you will always get the same result. That's what "immutable" means.
I'm not sure what you mean by a guaranteed value. There is no guarantee that a promise will ever resolve. It might reject (and thus not have a value) or it might never resolve or reject if the operation just never completes.
An example of the type of operation promises are designed for is an asynchronous operations such as an Ajax call or reading some bytes from a file. The operation is asynchronous (normal execution of the interpreter continues after the operation was started) and the operation has a specific start and end to it. In most case, the operation may complete successfully in which case it can have a value or it may end with an error in which case it has an error. Both value and error can be objects so they can have many properties if the result is more than a simple value.
An Ajax call, for example has a specific start and end. It can't end more than once so it is a perfect match for promises. You get a promise that signifies the eventual result of the ajax operation. You then register both a fulfill handler and a reject handler and one or the other will be called when the operation has completed.
Plain callbacks are just callbacks and they can be given a different value every time they are called and they can be called more than once.
If you want to get notified once and only once when some operation completes and the operation has a specific begin and end, use a promise.
If you want to get notified more than once, use a plain callback or an event listener or an observer or some other mechanism that can be trigger more than once.
As a simple example, setTimeout()
works very well with a promise.
function delay(t) {
return new Promise((resolve, reject) => {
resolve();
}, t);
}
// delay 100ms before starting the operation
delay(100).then(run);
Or, a little more involved operation using the Bluebird Promise library to cycle through a list of URLs, download the content, parse the content, look in the content for some specific URLs and then collect them all (otherwise known as scraping):
const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'), {multiArgs: true});
const cheerio = require('cheerio');
function getAsync() {
return request.getAsync.apply(request, arguments).then(argArray => {
// return only the response html
if (argArray[0].statusCode !== 200) {
throw new Error("response statusCode = " + argArray[0].statusCode);
}
return argArray[1];
});
}
const urls = [....];
Promise.mapSeries(urls, url => {
return getAsync({url: url, gzip: true}).then(html => {
let $ = cheerio.load(html);
let resources = $("#external_resources_list li a.filename");
resources.each(index, link) => {
let href = $(link).attr("href");
console.log(href);
results.push(href);
});
}).catch(err => {
// log error, but keep going
console.log(url, err);
});
}).then(() => {
// got all results here
console.log(results);
});
And, setInterval()
does not work at all with a promise because it wants to notify you repeatedly everytime the time interval passes and that will simply not work with promises. Stick with a callback for setInterval()
.