gildas-lormeau/zip.js

The 'closed' Promise Always in a pending state in Chromium 78

shay-an opened this issue · 3 comments

Help Me!

My code:

var zipWriter = new zip.ZipWriter(new zip.BlobWriter('application/zip'))
    await Promise.all(
      _.map(files, async (file) => {
        await zipWriter.add(file.name, new zip.BlobReader(file), {
          bufferedWrite: true,
          password: password,
          signal,
          zipCrypto: true,
          onprogress: (index, max) => {
          },
        })
      })
    )

// Not running at here
 let data = await zipWriter.close()
 console.log(data)

Running on Chrome is normal
After my debugging, I have located here:
At /lib/core/codec-worker.js

function watchClosedStream(writableSource) {
	const writer = writableSource.getWriter();
	let resolveStreamClosed;
	const closed = new Promise(resolve => resolveStreamClosed = resolve);
	const writable = new WritableStream({
		async write(chunk) {
			await writer.ready;
			await writer.write(chunk);
		},
		close() {
                        // Not running at here
			writer.releaseLock();
			resolveStreamClosed();
		},
		abort(reason) {
			return writer.abort(reason);
		}
	});
	return { writable, closed };
}

The browser download URL https://browser.360.cn/ee/mac/index.html
System : Mac os 10.15.7 (19H15)

I tried to reproduce your bug with the latest version of 360 speed browser. The test can be found here: https://plnkr.co/edit/HwnrHqehd05quud3?open=lib%2Fscript.js&preview.

Here is the code of the test below.

<!doctype html>

<html>

<head>
  <title>Adding concurrently multiple entries in a zip file</title>
</head>

<body>
  <script type="module">

    import * as zip from "https://unpkg.com/@zip.js/zip.js/index.js";

    const MB = 1024 * 1024;
    const ENTRIES_DATA = [
      { name: "entry #1", blob: getBlob(8.5 * MB) },
      { name: "entry #2", blob: getBlob(5.2 * MB) },
      { name: "entry #3", blob: getBlob(4.7 * MB) },
      { name: "entry #4", blob: getBlob(2.8 * MB) },
      { name: "entry #5", blob: getBlob(1.9 * MB) },
      { name: "entry #6", blob: getBlob(2.2 * MB) },
      { name: "entry #7", blob: getBlob(5.1 * MB) },
      { name: "entry #8", blob: getBlob(2.6 * MB) },
      { name: "entry #9", blob: getBlob(3.1 * MB) },
      { name: "entry #10", blob: getBlob(8.5 * MB) },
      { name: "entry #11", blob: getBlob(5.2 * MB) },
      { name: "entry #12", blob: getBlob(4.7 * MB) },
      { name: "entry #13", blob: getBlob(2.8 * MB) },
      { name: "entry #14", blob: getBlob(1.9 * MB) },
      { name: "entry #15", blob: getBlob(2.2 * MB) },
      { name: "entry #16", blob: getBlob(5.1 * MB) },
      { name: "entry #17", blob: getBlob(2.6 * MB) },
      { name: "entry #18", blob: getBlob(3.1 * MB) }];

    function getBlob(size) {
      const data = new Float64Array(Math.floor(size / 8));
      for (let indexData = 0; indexData < data.length; indexData++) {
        data[indexData] = Math.random();
      }
      return new Blob([data]);
    }

    async function test() {
      const controller = new AbortController();
      const signal = controller.signal;
      const blobWriter = new zip.BlobWriter("application/zip");
      const zipWriter = new zip.ZipWriter(blobWriter);
      await Promise.all(ENTRIES_DATA.map(entryData =>
        zipWriter.add(entryData.name, new zip.BlobReader(entryData.blob), {
          bufferedWrite: true,
          password: "password",
          signal,
          zipCrypto: true,
          onprogress: (index, max) => {
          }
        })));
      await zipWriter.close();
      document.body.innerHTML = "OK";
    }

    test();

  </script>
</body>

</html>

On my end, "OK" is always displayed in the page and everything works as expected. What changes should be applied to this code in order to reproduce your bug?

Hello!
My browser version is 12.2.1664.0
Chromium core version is 78

https://plnkr.co/edit/IsuSY533fDonkC8R
Here is the code of the test below.

<!doctype html>

<html>

<head>
  <title>Adding concurrently multiple entries in a zip file</title>
</head>

<body>
  <script type="module">

    import * as zip from "https://unpkg.com/@zip.js/zip.js/index.js";

    const MB = 1024 * 1024;
    const ENTRIES_DATA = [
      { name: "entry #1", blob: getBlob(8.5 * MB) },
      { name: "entry #2", blob: getBlob(5.2 * MB) },
      { name: "entry #3", blob: getBlob(4.7 * MB) },
      { name: "entry #4", blob: getBlob(2.8 * MB) },
      { name: "entry #5", blob: getBlob(1.9 * MB) },
      { name: "entry #6", blob: getBlob(2.2 * MB) },
      { name: "entry #7", blob: getBlob(5.1 * MB) },
      { name: "entry #8", blob: getBlob(2.6 * MB) },
      { name: "entry #9", blob: getBlob(3.1 * MB) },
      { name: "entry #10", blob: getBlob(8.5 * MB) },
      { name: "entry #11", blob: getBlob(5.2 * MB) },
      { name: "entry #12", blob: getBlob(4.7 * MB) },
      { name: "entry #13", blob: getBlob(2.8 * MB) },
      { name: "entry #14", blob: getBlob(1.9 * MB) },
      { name: "entry #15", blob: getBlob(2.2 * MB) },
      { name: "entry #16", blob: getBlob(5.1 * MB) },
      { name: "entry #17", blob: getBlob(2.6 * MB) },
      { name: "entry #18", blob: getBlob(3.1 * MB) }];

    function getBlob(size) {
      const data = new Float64Array(Math.floor(size / 8));
      for (let indexData = 0; indexData < data.length; indexData++) {
        data[indexData] = Math.random();
      }
      return new Blob([data]);
    }

    async function test() {
      const controller = new AbortController();
      document.body.innerHTML = "1";
      const signal = controller.signal;
      document.body.innerHTML = "2";
      const blobWriter = new zip.BlobWriter("application/zip");
      document.body.innerHTML = "3";
      const zipWriter = new zip.ZipWriter(blobWriter);
      document.body.innerHTML = "4";
      await Promise.all(ENTRIES_DATA.map(entryData =>
        zipWriter.add(entryData.name, new zip.BlobReader(entryData.blob), {
          bufferedWrite: true,
          password: "password",
          signal,
          zipCrypto: true,
          onprogress: (index, max) => {
          }
        })));
      document.body.innerHTML = "5";
      await zipWriter.close();
      document.body.innerHTML = "OK";
    }

    test();

  </script>
</body>

</html>

Always display "4"

But I upgraded my browser to the latest version, "OK" is always displayed in the page and everything works as expected.
This new browser version 14.5.0000.0
Chromium core version is 108

Does it not support versions as low as 78?

Thank you for the additional info, I was able to reproduce the bug in Chromium 78. The version 2.7.16 that I've just published should fix the issue.