Skip to content

Instantly share code, notes, and snippets.

@SebastianHGonzalez
Last active May 7, 2020 14:18
Show Gist options
  • Save SebastianHGonzalez/d7cc4b43046fa5030fc233bb0053164e to your computer and use it in GitHub Desktop.
Save SebastianHGonzalez/d7cc4b43046fa5030fc233bb0053164e to your computer and use it in GitHub Desktop.
Polljs
/**
* 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);
}
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