George Hotelling - Progressive Leasing
spotifyApi.clientCredentialsGrant(function(err, credentials) {
if (err) return err;
spotifyApi.setAccessToken(credentials.body['access_token']);
return spotifyApi.getPlaylist('spotify', 'NewMusicFriday', function postPlaylist(err, spotifyRes) {
if (err) return err;
return reddit('/api/submit').post({
'api_type': 'json',
'kind': 'link',
'resubmit': true,
'sendreplies': false,
'sr': config.reddit.subreddit,
'title': _.get(spotifyRes, 'body.name') + ' - ' + moment().format('MMMM Do, YYYY'),
'url': _.get(spotifyRes, 'body.external_urls.spotify')
}, function(err, redditPostRes) {
if (err) return err;
return reddit('/api/set_subreddit_sticky').post({
id: redditPostRes.json.data.name,
num: 1,
state: true
}, function(err) {
if (err) return err;
var trackPosted = [].fill(false, 0, spotifyRes.body.tracks.items.length - 1);
for (var i=0; i < spotifyRes.body.tracks.items.length; i++) {
var item = spotifyRes.body.tracks.items[i];
var artists = item.track.artists.map((a) => a.name).join(', ');
var title = artists + ' - ' + item.track.name;
reddit('/api/comment').post({
'api_type': 'json',
'text': '[' + title + '](' + _.get(item, 'track.external_urls.spotify') + ')',
'thing_id': spotifyRes.reddit.json.data.name
}, function(err) {
if (err) return err;
console.log('Posted ' + title);
trackPosted[i] = true;
if (trackPosted.every((trackDone) => trackDone)) {
console.log('DONE!');
}
});
}
});
});
});
});
spotifyApi.clientCredentialsGrant(function (err, credentials) {
if (err) return err;
spotifyApi.setAccessToken(credentials.body['access_token']);
return spotifyApi.getPlaylist('spotify', 'NewMusicFriday', postPlaylist);
});
var spotifyRes;
function postPlaylist(err, spotifyResArg) {
if (err) return err;
spotifyRes = spotifyResArg;
return reddit('/api/submit').post({
'api_type': 'json',
'kind': 'link',
'resubmit': true,
'sendreplies': false,
'sr': config.reddit.subreddit,
'title': _.get(spotifyRes, 'body.name') + ' - ' + moment().format('MMMM Do, YYYY'),
'url': _.get(spotifyRes, 'body.external_urls.spotify')
}, stickyPlaylist);
}
function stickyPlaylist(err, redditPostRes) {
if (err) return err;
return reddit('/api/set_subreddit_sticky').post({
id: redditPostRes.json.data.name,
num: 1,
state: true
}, postTracks);
}
var trackPosted;
function postTracks(err) {
if (err) return err;
trackPosted = [].fill(false, 0, spotifyRes.body.tracks.items.length - 1);
for (var i = 0; i < spotifyRes.body.tracks.items.length; i++) {
var item = spotifyRes.body.tracks.items[i];
var artists = item.track.artists.map((a) => a.name).join(', ');
var title = artists + ' - ' + item.track.name;
reddit('/api/comment').post({
'api_type': 'json',
'text': '[' + title + '](' + _.get(item, 'track.external_urls.spotify') + ')',
'thing_id': spotifyRes.reddit.json.data.name
}, onTrackPosted(title, i));
}
}
function onTrackPosted(title, i) {
return function (err) {
if (err) return err;
console.log('Posted ' + title);
trackPosted[i] = true;
if (trackPosted.every((trackDone) => trackDone)) {
console.log('DONE!');
}
}
}
It is a Promise for a value. Eventually.
For when you want to pass around a value you don't have yet.
.then()
.catch()
var promise = new Promise(function(resolve, reject) {
try {
…
resolve(value);
} catch(e) {
reject(e);
}
}));
Promise.resolve()
var resolvedPromise = Promise.resolve(foo);
Promise.reject()
var rejectededPromise = Promise.reject(bar);
spotifyApi.clientCredentialsGrant()
.then(function(credentials) {
spotifyApi.setAccessToken(credentials.body['access_token']);
spotifyApi.getPlaylist('spotify', 'NewMusicFriday');
})
spotifyApi.clientCredentialsGrant()
.then(function(credentials) {
spotifyApi.setAccessToken(credentials.body['access_token']);
spotifyApi.getPlaylist('spotify', 'NewMusicFriday')
.then(function (playlist) {
reddit('/api/submit').post({
'api_type': 'json',
'kind': 'link',
'resubmit': true,
'sendreplies': false,
'sr': 'NewMusicFriday',
'title': _.get(playlist, 'body.name') + ' - ' + moment().format('MMMM Do, YYYY'),
'url': _.get(playlist, 'body.external_urls.spotify')
});
});
});
Calling .then()
inside .then()
var playlistPromise = new Promise(function(resolve, reject) {
spotifyApi.clientCredentialsGrant()
.then(function(credentials) {
spotifyApi.setAccessToken(credentials.body['access_token']);
spotifyApi.getPlaylist('spotify', 'NewMusicFriday')
.then(resolve)
})
});
playlistPromise.then(function(playlist) {
reddit('/api/submit').post({
…
'sr': 'NewMusicFriday',
'title': _.get(playlist, 'body.name') + ' - ' + moment().format('MMMM Do, YYYY'),
'url': _.get(playlist, 'body.external_urls.spotify')
})
});
You (almost) never need to create a new, pending Promise!
Promise.resolve()
and Promise.reject()
are OK
.then()
Rule #1If you return a Promise from a .then()
the outer Promise becomes the inner Promise
spotifyApi.clientCredentialsGrant()
.then(function(credentials) {
spotifyApi.setAccessToken(credentials.body['access_token']);
return spotifyApi.getPlaylist('spotify', 'NewMusicFriday');
})
.then(function(playlist) {
reddit('/api/submit').post({
'api_type': 'json',
'kind': 'link',
'resubmit': true,
'sendreplies': false,
'sr': 'NewMusicFriday',
'title': _.get(playlist, 'body.name') + ' - ' + moment().format('MMMM Do, YYYY'),
'url': _.get(playlist, 'body.external_urls.spotify')
})
})
var credentialPromise = spotifyApi.clientCredentialsGrant();
var playlistPromise = credentialPromise.then(function(credentials) {
spotifyApi.setAccessToken(credentials.body['access_token']);
return spotifyApi.getPlaylist('spotify', 'NewMusicFriday');
});
var redditPostPromise = playlistPromise.then(function(playlist) {
reddit('/api/submit').post({
'api_type': 'json',
'kind': 'link',
'resubmit': true,
'sendreplies': false,
'sr': 'NewMusicFriday',
'title': _.get(playlist, 'body.name') + ' - ' + moment().format('MMMM Do, YYYY'),
'url': _.get(playlist, 'body.external_urls.spotify')
})
});
.then()
Rule #2If you return nothing from a .then()
, the Promise value stays the same.
spotifyApi.clientCredentialsGrant()
.then(saveAccessToken)
.then(getPlaylist)
.then(postPlaylist)
function saveAccessToken(credentials) {
spotifyApi.setAccessToken(credentials.body['access_token']);
}
function getPlaylist() {
return spotifyApi.getPlaylist('spotify', 'NewMusicFriday');
}
function postPlaylist(playlist) {
return reddit('/api/submit').post({…});
}
spotifyApi.clientCredentialsGrant()
.then(saveAccessToken)
.then(getPlaylist)
.then(postPlaylist)
.then(stickyPlaylist)
…
function stickyPlaylist(redditPostRes) {
return reddit('/api/set_subreddit_sticky').post({
id: redditPostRes.json.data.name,
num: 1,
state: true
});
}
spotifyApi.clientCredentialsGrant()
.then(saveAccessToken)
.then(getPlaylist)
.then(postPlaylist)
.then(stickyPlaylist)
.then(postTracks)
…
function postTracks(???) {
}
Promise.all()
spotifyApi.clientCredentialsGrant()
.then(saveAccessToken)
.then(getPlaylist)
.then(postPlaylist)
.then(stickyPlaylist)
…
function postPlaylist(playlist) {
return Promise.all([playlist, reddit('/api/submit').post({…})]);
}
function stickyPlaylist(playlist, redditPost) {
return Promise.all([playlist, redditPost, reddit('/api/set_subreddit_sticky').post({…})]);
}
spotifyApi.clientCredentialsGrant()
.then(saveAccessToken)
.then(getPlaylist)
.then(postPlaylist)
.then(stickyPlaylist)
.then(postTracks)
…
function postTracks(playlist, redditPost) {
return Promise.all(playlist.body.tracks.items.map(function(item) {
var artists = item.track.artists.map((a) => a.name).join(', ');
var title = artists + ' - ' + item.track.name;
return reddit('/api/comment').post({
'api_type': 'json',
'text': '[' + title + '](' + _.get(item, 'track.external_urls.spotify') + ')',
'thing_id': redditPost.json.data.name
})
.then(function() {
console.log('Posted ' + title);
});
}));
}
spotifyApi.clientCredentialsGrant(function (err, credentials) {
if (err) return err;
…
});
function postPlaylist(err, spotifyResArg) {
if (err) return err;
…
}
function stickyPlaylist(err, redditPostRes) {
if (err) return err;
…
}
function postTracks(err) {
if (err) return err;
…
}
function onTrackPosted(title, i) {
return function (err) {
if (err) return err;
…
}
}
}
spotifyApi.clientCredentialsGrant()
.then(saveAccessToken)
.then(getPlaylist)
.then(postPlaylist)
.then(stickyPlaylist)
.then(postTracks)
.then(console.log.bind(console, 'DONE!'))
.catch(console.error.bind(console))
function postTracks(playlist, redditPost) {
return Promise.all(playlist.body.tracks.items.map(function(item) {
var artists = item.track.artists.map((a) => a.name).join(', ');
if (/bieber/i.test(artists)) {
throw 'Not a Belieber!';
}
var title = artists + ' - ' + item.track.name;
return reddit('/api/comment').post({
'api_type': 'json',
'text': '[' + title + '](' + _.get(item, 'track.external_urls.spotify') + ')',
'thing_id': redditPost.json.data.name
})
.then(function() {
console.log('Posted ' + title);
});
}));
}
Not having a .catch()
statement.
async
await
try {
let credentials = await spotifyApi.clientCredentialsGrant();
spotifyApi.setAccessToken(credentials.body['access_token']);
let playlist = await getPlaylist();
let redditPost = await postPlaylist(playlist);
await Promise.all([
stickyPlaylist(playlist, redditPost),
postTracks(playlist, redditPost)
]);
console.log('DONE!');
} catch (err) {
console.error(err);
}
async function postPlaylist(playlist) {
return reddit('/api/submit').post({…});
}
.then()
Rules:.then()
the outer Promise becomes the inner Promise.then()
, the Promise value stays the same..then()
, the Promise value becomes that valuePromise.resovle()
Promise.reject()
Promise.all()
Promise.race()
- first value in array to resolve.then()
inside .then()
.catch()
statement.Slides up on https://github.com/georgeh/
Ask in the #javascript room in Slack