Last active
May 7, 2020 14:18
-
-
Save SebastianHGonzalez/d7cc4b43046fa5030fc233bb0053164e to your computer and use it in GitHub Desktop.
Polljs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Given an async function it will be executed until: | |
* - maxAttempts has been reached | |
* - it resolves | |
* - continueRef turned false | |
* | |
* Based off Trey Huffine's article: https://levelup.gitconnected.com/polling-in-javascript-ab2d6378705a | |
* Adapted to work on react components | |
* | |
* @param {Function} fn async function to execute. | |
* @param {number} interval time to wait between calls in ms. | |
* @param {Array} args arguments passed to function. | |
* @param {number} maxAttempts try attempts. 0 or negative number for infinite attempts. | |
* @param {{ current: Boolean }} continueRef cut off reference. | |
*/ | |
export default function poll( | |
fn: Function, | |
interval: number = 1000, | |
args: any[] = [], | |
maxAttempts: number = 0, | |
continueRef: { current: boolean } = { current: true } | |
) { | |
let remainingAttempts = maxAttempts; | |
const execute = async (resolve, reject) => { | |
remainingAttempts--; | |
try { | |
// Execute async | |
const result = await fn(...args); | |
// If result is still relevant resolve it | |
if (continueRef.current) { | |
return resolve(result); | |
} else { | |
return reject(new Error("aborted")); | |
} | |
} catch (e) { | |
// Check if the polling was aborted | |
if (!continueRef.current) { | |
return reject(new Error("aborted")); | |
} else if (!remainingAttempts) { | |
return reject(new Error("Exceeded max attemps")); | |
} else { | |
// Start over | |
setTimeout(execute, interval, resolve, reject); | |
} | |
} | |
}; | |
return new Promise(execute); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState, useEffect, useRef } from "react"; | |
import poll from "./poll"; | |
function unreliableOperation(param) { | |
return new Promise((resolve, reject) => { | |
setTimeout(() => { | |
const succeed = Math.random() * 100 > 75; | |
if (succeed) { | |
resolve(42); | |
} else { | |
reject(new Error()); | |
} | |
}, Math.random() * 1000); | |
}); | |
} | |
export default function useExample(param, relevant) { | |
const [result, setResult] = useState(null); | |
const [loading, setLoading] = useState(true); | |
const [error, setError] = useState(null); | |
const continueRef = useRef(true); | |
continueRef.current = relevant; | |
useEffect(() => { | |
if (!continueRef.current) return () => {}; | |
const interval = 2000; | |
const maxAttempts = 3; | |
poll(unreliableOperation, interval, [param], maxAttempts, continueRef) | |
.then((r) => { | |
if (continueRef.current) { | |
setResult(r); | |
} | |
}) | |
.catch(setError) | |
.finally(() => { | |
setLoading(false); | |
}); | |
return () => { | |
continueRef.current = false; | |
}; | |
}, [param]); | |
return [ | |
result, | |
{ | |
loading, | |
error, | |
}, | |
]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment