Whenever you return from a .then() clause, the returned value is wrapped with a promise, so you can chain promises together. You also need a only single .catch() clause to handle all errors in the chain before it.
In your case you can use LyricsCommand.getSongPageURL, and LyricsCommand.getLyrics as the callback for .then(), since they need only the previous value (url), and will return a url for the next step. The message.reply function can used be in the same way for the .catch() block.
LyricsCommand.searchSong(songName)
.then(LyricsCommand.getSongPageURL)
.then(LyricsCommand.getLyrics)
.then(function(lyrics) {
// .......... do something ..........
})
.catch(message.reply);
If you want to compose promises in a functional way, you'll need to create a compose function that can handle promises (taken from this article).
const composePromise = (...functions) =>
initialValue =>
functions.reduceRight(
(sum, fn) => Promise.resolve(sum).then(fn),
initialValue
);
Example (using SpaceX API):
const composePromise = (...functions) =>
initialValue => functions.reduceRight(
(sum, fn) => Promise.resolve(sum).then(fn),
initialValue
)
const fn = composePromise(
console.log,
data => data.rocket.rocket_id,
res => res.json(),
url => fetch(url, { method: 'get' })
)
const url = 'https://api.spacexdata.com/v2/launches/latest';
fn(url).catch(console.log)
This is how you'll use composePromise with your code:
const fn = composePromise(
lyrics => // do something with lyrics
LyricsCommand.getLyrics,
LyricsCommand.getSongPageURL,
LyricsCommand.searchSong
)
and you'll call it like this:
fn(songName).catch(message.reply)