私は、既存のAPIにファイルをアップロードする機能を持つアプリを開発しています。このAPIはJSONオブジェクトのファイルメタデータとコンテンツの両方を取得するので、ファイルのバイナリコンテンツをbase64エンコードされた文字列に変換する必要があります。大規模な配列を処理するときにWebワーカーがメモリ不足になる
これは潜在的に重い操作なので、私はその機能をWebワーカーに移しました。作業者は、バイナリファイルの内容(FileReader.readAsArrayBuffer()
から返された)を持つArrayBuffer
オブジェクトを取り込み、base64でエンコードされた文字列を返します。
これは小さいファイルでは問題ありませんが、私がサポートしなければならない最大のファイル(〜40 MB)では、ワーカー(Internet Explorerでは8007000E)のメモリ不足例外が発生します。まれにそれは通り抜けますが、ほとんどの場合、労働者はちょうど死ぬでしょう。ブラウザのページ全体がクラッシュした(IEとChromeの両方で)場合を除いて、同じことがワーカーに移動する前に同じことが起こりました。 Chromeは、IEよりも労働者のメモリストレスに対して少し弾力性があるようですが、IE(10+)でも正しく動作させる必要があります。
私の労働者:
onmessage = e => {
const bytes = new Uint8Array(e.data);
const l = bytes.length;
const chars = new Array(l);
for (let i = 0, j = l - 1; i <= j; ++i, --j) {
chars[i] = String.fromCharCode(bytes[i]);
chars[j] = String.fromCharCode(bytes[j]);
}
const byteString = chars.join('');
const base64bytes = btoa(byteString);
try {
postMessage(base64bytes, [base64bytes]);
} catch (e) {
postMessage(base64bytes);
}
};
が、私はここにいくつかの大きなノー-NOSを作っていますか?メモリ消費を減らす方法はありますか?私が考えた解決策の1つは、ファイル全体ではなくチャンクでコンテンツを処理し、結果の文字列を連結して外部にエンコードすることです。それは実行可能か、それともそれ自身の問題を引き起こすでしょうか?私が知らない他の魔法の機能はありますか?私はFileReader.readAsBinaryString()
で希望の光沢がありましたが、現在は標準から削除されています(とにかくIE10でサポートされていない)ので、使用できません。私が考えた
(私はこの質問はあまりにもコードレビューで関連するかもしれないが、私のコードが実際にクラッシュされているので、私はSO正しい場所だった考え出し実現)
ないそれはあなたの問題を解決に関連していますかどうかわからが、なぜ 'chars'を埋めます各端から始まり中央に仕上げますか? –
これは、最適化の試行であったため、反復回数を40MBから20Mに半減します。それはちょっと行ってしまう前に処理できるサイズを増やしましたが、まだ最大のファイルでは不十分です。 –