Skip to content

Commit

Permalink
improve and update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
101arrowz committed Sep 3, 2023
1 parent cf98805 commit 9698440
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 10 deletions.
9 changes: 7 additions & 2 deletions README.md
Expand Up @@ -531,10 +531,15 @@ Note that there exist some small libraries like [`tiny-inflate`](https://npmjs.c

So what makes `fflate` different? It takes the brilliant innovations of `UZIP.js` and optimizes them while adding direct support for GZIP and Zlib data. And unlike all of the above libraries, it uses ES Modules to allow for partial builds through tree shaking, meaning that it can rival even `tiny-inflate` in size while maintaining excellent performance. The end result is a library that, in total, weighs 8kB minified for the core build (3kB for decompression only and 5kB for compression only), is about 15% faster than `UZIP.js` or up to 60% faster than `pako`, and achieves the same or better compression ratio than the rest.

If you're willing to have 160 kB of extra weight and [much less browser support](https://caniuse.com/wasm), you could theoretically achieve more performance than `fflate` with a WASM build of Zlib like [`wasm-flate`](https://www.npmjs.com/package/wasm-flate). However, per some tests I conducted, the WASM interpreters of major browsers are not fast enough as of December 2020 for `wasm-flate` to be useful: `fflate` is around 2x faster.

Before you decide that `fflate` is the end-all compression library, you should note that JavaScript simply cannot rival the performance of a native program. If you're only using Node.js, it's probably better to use the [native Zlib bindings](https://nodejs.org/api/zlib.html), which tend to offer the best performance. Though note that even against Zlib, `fflate` is only around 30% slower in decompression and 10% slower in compression, and can still achieve better compression ratios!

## What about `CompressionStream`?
Like `fflate`, the [Compression Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Compression_Streams_API) provides DEFLATE, GZIP, and Zlib compression and decompression support. It's a good option if you'd like to compress or decompress data without installing any third-party libraries, and it wraps native Zlib bindings to achieve better performance than what most JavaScript programs can achieve.

However, browsers do not offer any native non-streaming compression API, and `CompressionStream` has surprisingly poor performance on data already loaded into memory; `fflate` tends to be faster even for files that are dozens of megabytes large. Similarly, `fflate` is much faster for files under a megabyte because it avoids marshalling overheads. Even when streaming hundreds of megabytes of data, the native API usually only performs between 5% slower and 10% faster than `fflate`. And Compression Streams have many other disadvantages - no ability to control compression level, poor support for older browsers, no ZIP support, etc.

If you'd still prefer to depend upon a native browser API, you can use an `fflate`-based [Compression Streams ponyfill](https://github.com/101arrowz/compression-streams-polyfill) for a seamless transition to `CompressionStream` and `DecompressionStream` if ever they become substantially faster than `fflate`.

## Browser support
`fflate` makes heavy use of typed arrays (`Uint8Array`, `Uint16Array`, etc.). Typed arrays can be polyfilled at the cost of performance, but the most recent browser that doesn't support them [is from 2011](https://caniuse.com/typedarrays), so I wouldn't bother.

Expand Down
16 changes: 9 additions & 7 deletions demo/components/code-box/index.tsx
Expand Up @@ -199,18 +199,20 @@ for (var i = 0; i < files.length; ++i) {
}`,
pako: `var left = files.length;
// Internally, this uses JSZip. Despite its clean API, it suffers from
// abysmal performance and awful compression ratios, particularly in v3.2.0
// and up.
// If you choose JSZip, make sure to use v3.1.5 for adequate performance
// (2-3x slower than fflate) instead of the latest version, which is 20-30x
// slower than fflate.
// Internally, this uses JSZip. This library used to be unusuably slow but
// has recently improved. Still, it's 2-3x slower than fflate as of v3.10.1,
// offers a convoluted API, and is several times larger in bundle size while
// providing no useful features unavailable in similar ZIP libraries.
// If you need a performant ZIP library with a wider API than fflate, try
// @zip.js/zip.js instead. You can even use it
var zipObj = pakoWorker.zip();
var processFile = function(i) {
var file = files[i];
fileToU8(file, function(buf) {
// With JSZip, you cannot control the compression level of a file
// JSZip allows you to control per-file compression level. For this demo,
// the list of non-compressed files is the same as for fflate.
zipObj.add(file.name, buf);
if (!--left) {
zipObj.ondata = function(err, out) {
Expand Down
11 changes: 10 additions & 1 deletion demo/util/workers.ts
Expand Up @@ -47,14 +47,23 @@ const uzGzip = (d: Uint8Array) => {
return concat([head, raw, tail]);
}

const ALREADY_COMPRESSED = [
'zip', 'gz', 'png', 'jpg', 'jpeg', 'pdf', 'doc', 'docx', 'ppt', 'pptx',
'xls', 'xlsx', 'heic', 'heif', '7z', 'bz2', 'rar', 'gif', 'webp', 'webm',
'mp4', 'mov', 'mp3', 'aifc'
]

onmessage = (ev: MessageEvent<[string, string]>) => {
const [lib, type] = ev.data;
if (lib == 'pako') {
if (type == 'zip') {
const zip = new JSZip();
onmessage = (ev: MessageEvent<null | [string, Uint8Array]>) => {
if (ev.data) {
zip.file(ev.data[0], ev.data[1]);
const ext = ev.data[0].slice(ev.data[0].lastIndexOf('.') + 1).toLowerCase()
zip.file(ev.data[0], ev.data[1], {
compression: ALREADY_COMPRESSED.includes(ext) ? 'STORE' : 'DEFLATE'
});
} else zip.generateAsync({
type: 'uint8array',
compressionOptions: { level: 6 }
Expand Down

0 comments on commit 9698440

Please sign in to comment.