Skip to content

Instantly share code, notes, and snippets.

@ryunp
Created February 19, 2020 07:52
Show Gist options
  • Save ryunp/3121c2808a9303ca25fb6e24460c60be to your computer and use it in GitHub Desktop.
Save ryunp/3121c2808a9303ca25fb6e24460c60be to your computer and use it in GitHub Desktop.
/* Change files on filesystem and/or config to see error handling */
// Simulate configurations
config = { installPath: 'root/place/subplace' }
d2config = {
files: [
'a.dll',
'abc.txt',
'deeper/d.txt'
]
}
// Simulate filesystem
actualFiles = [
'root/place/subplace/a.dll',
'root/place/subplace/a.txt',
'root/place/subplace/ab.txt',
'root/place/subplace/abc.txt',
'root/place/subplace/deeper/d.txt'
]
function main () {
// Make absolute paths for OS calls
var files = d2config.files.map(f => pathJoin(config.installPath, f))
internalAPI.verifyFiles(files).then(onSuccess, onFailure)
function onSuccess (files) {
console.log(files) // > Array ["a.jpg", "abc.jpg", "d.jpg"]
}
function onFailure (error) {
console.log(error) // > Error: 2 file(s) missing
console.log(error.files) // > Array ["root/place/subplace/a.dll", "root/place/subplace/deeper/d.txt"]
}
}
/* OS Lib Functionality */
function pathJoin (...args) {
return args.join('/').replace(/\/+/, '/')
}
function accessAsync (path, flags) {
return new Promise(resolver)
function resolver (resolve, reject) {
setTimeout(mock_assertAsync, Math.random() * 2000)
function mock_assertAsync () {
if (actualFiles.indexOf(path) > -1) resolve(true)
else reject(Error)
}
}
}
function filesExistAsync (files) {
return Promise.all(files.map(createExistsPromise)).then(parseResults)
function createExistsPromise (file) {
return new Promise(resolver)
// Resolve() data whether found/missing for later processing
function resolver (resolve) {
const onFileFound = () => resolve({ file, error: false })
const onFileNotFound = (error) => resolve({ file, error })
accessAsync(file).then(onFileFound, onFileNotFound)
}
}
function parseResults (results) {
const missingFiles = results
.filter(obj => obj.error)
.map(obj => obj.file)
if (missingFiles.length) {
const error = new Error(`${missingFiles.length} file(s) missing`)
error.files = missingFiles
return Promise.reject(error)
}
return files
}
}
/* Separation of concerns lib, ex: diablo2.verifyFiles, diablo2.getProcesses, etc */
const internalAPI = {
verifyFiles (files) {
return (
filesExistAsync(files)
.then(changeExtensions)
.then(baseName)
)
function changeExtensions (files) {
return files.map(file => file.replace(/\..*/, '.jpg'))
}
function baseName (files) {
return files.map(f => f.split('/').pop())
}
}
}
/* Fire off instructions */
main()
function timedAsync (promiseCallback, delay) {
return new Promise(executor)
function executor (resolve, reject) {
console.log(`waiting ${delay}ms before execution...`)
setTimeout(dispatch, delay)
function dispatch () {
console.log(`${delay}ms elapsed, executing callback`)
promiseCallback().then(resolve, reject)
}
}
}
function asyncActionBuilder (state, iterations) {
const futureStateStr = state ? "succeed" : "fail"
console.log(`Building Promise to ${futureStateStr}...`)
return function asyncAction () {
return new Promise(executor)
function executor (resolve, reject) {
var counter = 0
const timer = setInterval(tick, 1000)
function tick () {
console.log(counter++)
if (counter > iterations) {
clearTimeout(timer)
if (state) resolve("We gootchie")
else reject("Ruh Roh")
}
}
}
}
}
timedAsync(asyncActionBuilder(true, 3), 2000).then(console.log, console.error)
/**
* Author: Ryan Paul
* Date: 04/13/19
* Description: Testing Double Promise.catch chain behavior, simulating
* a Discord bot environment
*/
function simulation (initialEditSuccess, resolutionSuccess) {
const message = {
edit: function edit (str) {
if (initialEditSuccess) {
return Promise.resolve(`Message edit success: ${str}`);
} else {
return Promise.reject(new Error("Message edit fail"));
}
}
}
// MOVE THE ERROR CATCH HERE FOR PARENT CATCH
return updateDiscordMessage("New text!")
.then(console.log);
// .catch(console.error);
function updateDiscordMessage (str) {
// MOVE THE ERROR CATCH HERE FOR DOUBLE CATCH
return message.edit(str).catch(attemptResolution).catch(console.error);
function attemptResolution () {
console.log("Attempting to recreate message...");
return recreateMessage().then(updateNewMessage);
function updateNewMessage (message) {
return message.edit(str);
}
}
}
function recreateMessage () {
const newMessage = {
edit: (str) => Promise.resolve(`NewMessage edit success: ${str}`)
};
return create();
function create () {
if (resolutionSuccess) {
return Promise.resolve(newMessage);
} else {
const error = new Error("Failed to create new Discord message");
return Promise.reject(error);
}
}
}
}
console.log("~~ Situation 1) Message already exists for editing ~~")
await simulation(true, true);
console.log("\n~~ Situation 2: Message was deleted during runtime between render updates ~~");
simulation(false, true);
/* OUTPUT
~~ Situation 1) Message already exists for editing ~~
Message edit success: New text!
~~ Situation 2: Message was deleted during runtime between render updates ~~
Attempting to recreate message...
NewMessage edit success: New text!
*/
function init() {
console.time('totalAsync')
testTimimgAsync().then(() => {
console.timeEnd('totalAsync')
})
console.time('totalPromise')
testTimimgPromise().then(() => {
console.timeEnd('totalPromise')
})
}
async function testTimimgAsync() {
const count = 10
for (let i=0; i<count; i++) {
console.time(`queryAsync-${i}`)
try {
await Registry.get(d2Config.registry.path, true)
console.timeEnd(`queryAsync-${i}`)
} catch(e) {
console.log(e)
}
}
}
function testTimimgPromise() {
const count = 10
const tasks = []
for (let i=0; i<count; i++) {
console.time(`queryPromise-${i}`)
let query = Registry.get(d2Config.registry.path, true)
.then(onSuccess)
.catch(console.error)
tasks.push(query)
function onSuccess(data) {
console.timeEnd(`queryPromise-${i}`)
}
}
return Promise.all(tasks)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment