Skip to content

Instantly share code, notes, and snippets.

@machuga
Last active March 22, 2019 21:07
Show Gist options
  • Save machuga/e0dae53637be1ed6b3a97923cfadc775 to your computer and use it in GitHub Desktop.
Save machuga/e0dae53637be1ed6b3a97923cfadc775 to your computer and use it in GitHub Desktop.
Grokkable Concurrent JavaScript - Teaching Asynchronous Patterns and Refactorings
const get = require('./get'); // get(url, callback)
const githubApi = 'https://api.github.com';
const githubEventsUrlFor = username => `${githubApi}/users/${username}/events`;
const githubRepoUrlFor = repo => `${githubApi}/repos/${repo}`;
const fetchReposForLatestActivity = (user, callback) => {
let timeout = setTimeout(function() {
callback(new Error('Timed out'));
}, 3000);
get(githubEventsUrlFor(user), (err, allEvents) => {
if (err) {
return callback(err);
}
const events = allEvents.slice(0, 3);
const repos = [];
let remainingCount = events.length;
events.forEach(event => {
get(githubRepoUrlFor(event.repo.name), (err, data) => {
if (err) {
return callback(err);
}
repos.push({
author: data.owner.login,
avatar: data.owner.avatar_url,
name: data.name,
full_name: data.full_name,
url: data.html_url,
description: data.description
});
remainingCount -= 1;
if (remainingCount <= 0) {
clearTimeout(timeout);
callback(null, repos)
}
});
});
});
};
fetchReposForLatestActivity('machuga', (err, repos) => {
if (err) {
console.error(err);
return;
}
console.log(repos);
});
const get = require('./get'); // get(url, callback)
const githubApi = 'https://api.github.com';
const githubEventsUrlFor = username => `${githubApi}/users/${username}/events`;
const githubRepoUrlFor = repo => `${githubApi}/repos/${repo}`;
const fetchRepo = (repoName, callback) => {
get(githubRepoUrlFor(repoName), callback);
};
const fetchEventsForUser = (user, callback) => {
get(githubEventsUrlFor(user), callback);
};
const fetchReposForEvents = (events, callback) => {
const repos = [];
let remainingCount = events.length;
events.forEach(event => {
fetchRepo(event.repo.name, (err, data) => {
if (err) {
return callback(err);
}
repos.push({
author: data.owner.login,
avatar: data.owner.avatar_url,
name: data.name,
full_name: data.full_name,
url: data.html_url,
description: data.description
});
remainingCount -= 1;
if (remainingCount <= 0) {
callback(null, repos)
}
});
});
};
const fetchReposForLatestActivity = (user, callback) => {
let timeout = setTimeout(function() {
callback(new Error('Timed out'));
}, 3000);
fetchEventsForUser(user, (err, allEvents) => {
if (err) {
return callback(err);
}
fetchReposForEvents(allEvents.slice(0, 3), (err, repos) => {
if (err) {
return callback(err);
}
clearTimeout(timeout);
callback(null, repos);
});
});
};
fetchReposForLatestActivity('sgrif', (err, repos) => {
if (err) {
console.error(err);
return;
}
console.log(repos);
});
const callbacks = [
(done) => { setTimeout(() => { done(null, '1') }, 500) },
(done) => { setTimeout(() => { done(null, '2') }, 200) },
];
const whenAllSettled = (fns, callback) => {
const results = [];
let remainingCount = fns.length;
const done = (i) => (err, result) => {
let resultObject;
if (err) {
resultObject = { type: 'failure', value: err };
} else {
resultObject = { type: 'success', value: result };
}
results[i] = resultObject;
remainingCount -= 1;
if (remainingCount <= 0) {
callback(null, results);
}
};
fns.forEach((fn, i) => {
fn(done(i));
});
}
whenAllSettled(callbacks, (err, results) => {
console.log("All done with round 1!", results);
whenAllSettled([
(done) => { setTimeout(() => done(new Error('oops')), 500); }
], (err, results) => {
console.log("All done with round 2!", results);
})
});
console.log("first");
setTimeout(function fifth() { console.log("fifth"); }, 500);
setTimeout(function third() { console.log("third"); }, 0);
setTimeout(function fourth() { console.log("fourth"); }, 0);
console.log("second");
const startTime = Date.now();
console.log("first at", startTime)
announceTick();
setTimeout(createTickLoggerFor("seventh"), 500);
setTimeout(createTickLoggerFor("third"), 0);
setTimeout(function differentTick() {
announceTick();
logWithOffset("fourth");
setTimeout(createTickLoggerFor("sixth"), 0);
for (let i = 0; i < 100000; i++) {
process.stdout.write(`Delaying: ${i}\r`);
}
console.log('\n');
logWithOffset("fifth");
setTimeout(createTickLoggerFor("eighth"), 300);
}, 0);
logWithOffset("second");
function timeFromStart() {
return Date.now() - startTime;
}
function createTickLoggerFor(msg) {
return function() {
announceTick();
logWithOffset(msg);
}
}
function logWithOffset(msg) {
console.log(`[Offset: ${timeFromStart()}]: ${msg}`);
}
function announceTick() {
process.nextTick(() => {
console.log("-----TICK-----")
});
}
@machuga
Copy link
Author

machuga commented Feb 19, 2019

Gist will not update 2 file to use 2 spaces or tabs. I am so sorry, internet. I have failed you 😢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment