-
-
Save asidko/9c7064027039411a11323eaf7d8ea2a4 to your computer and use it in GitHub Desktop.
// Paste the following example to browser console | |
// Comppreses string to GZIP. Retruns a Promise with Base64 string | |
const compress = string => { | |
const blobToBase64 = blob => new Promise((resolve, _) => { | |
const reader = new FileReader(); | |
reader.onloadend = () => resolve(reader.result.split(',')[1]); | |
reader.readAsDataURL(blob); | |
}); | |
const byteArray = new TextEncoder().encode(string); | |
const cs = new CompressionStream('gzip'); | |
const writer = cs.writable.getWriter(); | |
writer.write(byteArray); | |
writer.close(); | |
return new Response(cs.readable).blob().then(blobToBase64); | |
}; | |
// Decompresses base64 encoded GZIP string. Retruns a string with original text. | |
const decompress = base64string => { | |
const bytes = Uint8Array.from(atob(base64string), c => c.charCodeAt(0)); | |
const cs = new DecompressionStream('gzip'); | |
const writer = cs.writable.getWriter(); | |
writer.write(bytes); | |
writer.close(); | |
return new Response(cs.readable).arrayBuffer().then(function (arrayBuffer) { | |
return new TextDecoder().decode(arrayBuffer); | |
}); | |
} | |
///////////////////// | |
// Checking | |
///////////////////// | |
Promise.resolve("Hello GZIP!") | |
.then(v => { | |
console.log("Original value: %s", v); | |
return v; | |
}) | |
.then(v => compress(v)) | |
.then(v => { | |
console.log("Compressed value: %s", v); | |
return v; | |
}) | |
.then(v => decompress(v)) | |
.then(v => console.log("Decomporessed value: %s", v)); | |
Yeah ๐. There's a mixture of promise and classical code.
So we should wrap everything inside compress/decompress functions in Promise to make error follow it's .catch() flow, otherwise for current code you need both synchronous handling and promise handling:
try {
decompress("invalid$base64%#@").catch(e => console.log("Got a promise error when decompressing: " + e))
} catch (e) {
console.log("Got an synchronous error: " + e);
}
Result:
Got an error: InvalidCharacterError: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
So, it's better to wrap a whole function in Promise and move try-catch block there
const decompress = (base64string) => {
return new Promise((resolve, reject) => {
try {
const bytes = Uint8Array.from(atob(base64string), c => c.charCodeAt(0));
const cs = new DecompressionStream('gzip');
const writer = cs.writable.getWriter();
writer.write(bytes)
.then(() => writer.close())
.then(() => new Response(cs.readable).arrayBuffer())
.then(arrayBuffer => resolve(new TextDecoder().decode(arrayBuffer)))
.catch(reject); // Catch any errors in the promise chain
} catch (error) {
reject(error); // Catch any synchronous errors
}
});
};
// Trying it
decompress("invalid$base64%#@").catch(e => console.log("Got a promise error when decompressing: " + e))
// Result: just .catch() is enough now to handle all errors
Got a promise error when decompressing: InvalidCharacterError: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
Apologies for late re-reply. I just saw your answer after going thru my bookmarks.
I tried your codes and I don't know how to save the result into a var. Granted I'm still grasping on this whole Promise
technique.
Anyway, this is the code that I've been using since I asked that question. It catches the error, but somehow the error is still on the console claiming that it's still uncatched. I don't know why this code works, but it works. Maybe you want to check it out. The error message is in writer.closed
as far as I understand.
async function decomp(str,mode="gzip"){
// Using Node Buffer for encoder
str = Buffer.from(str, "base64")
const cs = new DecompressionStream(mode)
const writer = cs.writable.getWriter()
writer.write(str)
writer.close()
return await new Response(cs.readable).arrayBuffer()
.then(
// Resolve Function
arr=>(Buffer.from(arr)).toString("utf8"),
// Reject Function
async _=>{throw new Error(await Promise.reject(await writer.closed))}
)
}
let string = [
// "These strings were compressed!" compressed with gzip and base64 encoder
`H4sIAAAAAAAACgvJSC1OVSguKcrMSy9WKE8tSlVIzs8tKEotLk5NUQQAfREzrR4AAAA`,
// Change capital R near the end
`H4sIAAAAAAAACgvJSC1OVSguKcrMSy9WKE8tSlVIzs8tKEotLk5NUQQAfREzrr4AAAA`,
// Change 1 char at the end
`H4sIAAAAAAAACgvJSC1OVSguKcrMSy9WKE8tSlVIzs8tKEotLk5NUQQAfREzrR4AAAx`,
// Add 1 char at the end
`H4sIAAAAAAAACgvJSC1OVSguKcrMSy9WKE8tSlVIzs8tKEotLk5NUQQAfREzrR4AAAAx`,
],
result = []
console.clear()
for(let item of string){
try{
result.push(
"Succesfully decompressing!\n\n" + "String Result : "+ (await decomp(item))
)
}
catch(err){
result.push("Failed to decompress!\n\n"+ err.name +" : "+ err.message)
}
}
console.log(result.join("\n\n=====================================================================\n\n"))
Also an important question, is there a notification page somewhere in github? I just saw your reply. But I already subscribe to this post / gist. There must be notification somewhere, right?
Cheers
Thanks @asidko I was trying to roll my own version of this but ran into an error from the Response
: "TypeError: Failed to fetch". I believe it was something to do with my approach to base64 encoding. Your implementation worked a treat ๐
How do you catch the error?
I tried to decompress random Buffer bytes and got an error thrown
Uncaught (in promise) TypeError : The compress data was not valid. Invalid block data
.I tried to catch it with
.catch(err=>{console.log(err)})
but failed. Only gotTypeError : Failed to fetch
.I've been reading about async function and
Promise
, but still a dead end. Sorry if the question is too stupid or has an obvious answer.