I am trying to convert the way I use asynchronous functions from callbacks to promises.
I understand this basic conversion shown here, where callbacks are converted to the resolve and reject functions:
// CALLBACK
const getData = (id, callback) => {
setTimeout(() => {
if (!id) return callback('ERROR: id is missing')
return callback("The data for id " + id);
}, 1000)
};
getData(111, console.log);
getData(222, console.log);
getData(null, console.log);
// PROMISE
const getData2 = id => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!id) reject('id is missing');
resolve("The data for id " + id);
}, 1000);
});
};
getData2(333).then(console.log).catch((message) => console.log("ERROR: " + message));
getData2(444).then(console.log).catch((message) => console.log("ERROR: " + message));
getData2(null).then(console.log).catch((message) => console.log("ERROR: " + message));
But I often use callbacks as in the following scenerio where you can have a process which takes a long time and sends out bits of data in numerous callbacks back to the calling code as it processes its information:
sleep = function (ms) {
var start = new Date().getTime();
let now = 0;
let difference = 0;
for (var i = 0; i < 1e17; i++) {
now = new Date().getTime();
difference = now - start;
if (difference > ms) {
break;
}
}
}
const goShopping = (list, cbItemReport, cbFinished, cbError) => {
let count = 0;
let numberFound = 0;
const randomError = Math.floor(Math.random() * 3);
if (randomError == 0) {
cbError('Something went wrong, trip aborted.');
} else {
list.forEach(item => {
const randomFound = Math.floor(Math.random() * 4);
if (randomFound > 0) {
cbItemReport(item, true, ++count);
numberFound++;
} else {
cbItemReport(item, false, ++count);
}
sleep(1000);
})
cbFinished(`Bought ${numberFound} things.`);
}
}
goShopping(['milk', 'eggs', 'sugar', 'bread'],
(item, found, count) => {
console.log(`Item #${count} "${item}" was ${found ? 'found' : 'not found'}.`);
},
(message) => {
console.log("Returned from shopping: " + message);
},
(error) => {
console.log("ERROR: " + error);
});
How would I convert this latter use of callbacks to promises? In this case, the three callbacks cbItemReport, cbFinished, cbError are too many to map to the two that Promise has, i.e. only resolve (cbFinished) and reject (cbError), or what am I missing here?
From what it sounds like, you are looking to implement something like the RxJs library, so why not just use it?
Check out RxJs here
For example a call could look like this then:
const sub = new Subject(); // Create a subject
sub.asObservable().subscribe( // Subscribe to that subject as obserable
({item, found, count}) => { // next
console.log(`Item #${count} "${item}" was ${found ? 'found' : 'not found'}.`);
},
error => { // error
console.log("ERROR: " + error);
},
message => { // complete
console.log("Returned from shopping: " + message);
}
);
const goShopping = (list) => {
let count = 0;
let numberFound = 0;
const randomError = Math.floor(Math.random() * 3);
if (randomError == 0) {
sub.error('Something went wrong, trip aborted.'); // push an error to the subject
} else {
list.forEach(item => {
const randomFound = Math.floor(Math.random() * 4);
if (randomFound > 0) {
sub.next({item: item, found: true, count: ++count}); // push a result to subject (single object)
numberFound++;
} else {
sub.next({item: item, found: true, count: ++count}); // same as above
}
sleep(1000);
})
sub.complete(`Bought ${numberFound} things.`); // push complete to subject. after that no next is allowed anymore
}
}
goShopping(['milk', 'eggs', 'sugar', 'bread'])
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