Created
June 29, 2021 20:52
-
-
Save barelyhuman/d33a3b5882cfd6952491268782a7937b to your computer and use it in GitHub Desktop.
Make API calls synchronous in web workers using atomics
This file contains 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
// Simple js file that index.html has as a script src or the entry file of the app | |
let worker = new Worker("worker.js"); | |
worker.postMessage({ | |
url: "https://jsonplaceholder.typicode.com/todos/1", | |
}); |
This file contains 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
// just fetch returning text | |
const fetcher = (url) => { | |
return fetch(url).then((data) => data.text()); | |
}; | |
// Performing the needed async operation , this worker will run await on the needed method | |
const performAsync = async (url, sharedDataChan) => { | |
const data = await fetcher(url); | |
var valueStore = new Int32Array(sharedDataChan); | |
for (var i = 0, strLen = data.length; i < strLen; i++) { | |
valueStore[i] = data.charCodeAt(i); | |
} | |
}; | |
/* | |
listener - will wait for the first notification from the | |
main worker and then start processing the needed data | |
then it handles the needed task in the performAsync call | |
*/ | |
const listener = async ({ notifierChan, sharedDataChan, url }) => { | |
const notifierChannelMem = new Int32Array(notifierChan); | |
Atomics.wait(notifierChannelMem, 1, 1); | |
await performAsync(url, sharedDataChan); | |
Atomics.store(notifierChannelMem, 0, 1); | |
Atomics.notify(notifierChannelMem, 0, 1); | |
}; | |
/* | |
The initial message sent to everyone that are waiting on syncer that syncer | |
is now ready to listen for your data | |
*/ | |
onmessage = (msg) => { | |
postMessage(0); | |
const { data } = msg; | |
listener(data); | |
}; |
This file contains 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
let syncer = new Worker("syncer.js"); | |
// Channel to handle both the workers to trigger each other | |
let notifierChan = new SharedArrayBuffer(8); | |
// Channel the data will be shared on, in this case the API request data | |
let sharedDataChan = new SharedArrayBuffer(10000); | |
// ArrayBuffer to string | |
function bufferToString(buf) { | |
return String.fromCharCode | |
.apply(null, new Uint16Array(buf)) | |
.replace(/\u0000/g, ""); | |
} | |
// Function that notifies the child web worker to start doing the async task | |
// and then waits for it to complete | |
const loadUrl = () => { | |
const notifierChannelMem = new Int32Array(notifierChan); | |
const sharedArray = new Int32Array(sharedDataChan); | |
Atomics.notify(notifierChannelMem, 1, 1); | |
Atomics.wait(notifierChannelMem, 0, 0); | |
return bufferToString(sharedArray); | |
}; | |
// Wrapper function for loadUrl , you can just use loadUrk directly | |
const run = () => { | |
console.log(loadUrl()); | |
}; | |
// onmessage handler to get requests from the main thread | |
onmessage = (fromMain) => { | |
/* | |
Send the initial shared data channels before triggering a wait so the writer and | |
reader , in this case | |
writer - syncer.js | |
reader - worker.js | |
can actually be 2 threads and ready to actually handle everything | |
the writer(syncer.js) is waiting for a start notification from this worker | |
before running the async operation | |
*/ | |
syncer.postMessage({ | |
notifierChan: notifierChan, | |
sharedDataChan, | |
url: fromMain.data.url, | |
}); | |
// Trigger the handler once syncer says it's up | |
syncer.onmessage = (ev) => { | |
run(); | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment