###前提・実現したいこと
元々がカンマ区切りのデータを引数にとって
String.fromCharCode.applyで処理をしている箇所があります。
ファイルのデータが少ない際には問題ないのですが、
一定の容量になるとエラーになります。
原因としてはapplyの引数に渡せる個数に制限があるため、
一定容量を超えると使えなくなるようでした。
この制限を回避する方法はないでしょうか。
###試したこと
考えた事として制限としてかかっている数に分割して、
後に結合すればよいと単純に思いました。
ただしそのような処理をして正常な状態に戻るのかという疑問と、
バイナリデータ操作する方法が根本的によく分かりませんでした。
###発生している問題・エラーメッセージ
SCRIPT XX: スタック領域が不足しています。
###該当のソースコード
JavaScript
1var input = String.fromCharCode.apply(null, this.sampledata)
###補足情報(言語/FW/ツール等のバージョンなど)
ブラウザIE11
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/21 23:51
2017/09/22 05:58
回答4件
0
環境にもよるのかもしれませんが、ArrayBuffer
→Blob
として、FileReader
APIを使ったらエラーになりませんでした。
javascript
1var sampledata= Array(1000000).fill(97); 2//String.fromCharCode.apply(null, sampledata); ←これはエラー。 3var blob = new Blob( [new Uint8Array(sampledata).buffer] ); 4var reader = new FileReader(); 5reader.onload = function(e){ 6 console.log(reader.result); 7}; 8reader.readAsText(blob);
でも、ウチのFirefoxさんは10万字に耐えたので現実的にはfromCharCode
で十分な気も……
投稿2017/09/22 04:58
総合スコア36115
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/23 04:58
0
引数の数の制限についてStack Overflowに質問があったので紹介します。
Is there a max number of arguments JavaScript functions can accept?
上記質問の各回答によると、仕様としては制限はありません(ES5.1で述べていますが、最新のES8の6.2.1The List and Record Specification Typesも同じ文言です)。しかし、各ブラウザ毎に実装上の制限は存在するようで、その制限値もブラウザによって異なります。また、スタック不足のエラーメッセージとなっていますが、単なるスタックオーバーフローであるとか、そう単純な話でも無いようです。
とりあえず、制限はあります。32767以下でないと安全とは言えないでしょう。では、バラバラに処理して、文字列を結合させて問題ないかというと問題ありません。下記のテスト用コードを実行してみてください。
JavaScript
1"use strict"; 2function stringToCharCodeList(str) { 3 return Array.prototype.map.call(str, function(c) { 4 return c.charCodeAt(0); 5 }); 6} 7 8function charCodeListToString(list) { 9 return String.fromCharCode.apply(null, list); 10} 11 12function charCodeListToStringSplit(list) { 13 return list.reduce(function(str, code) { 14 return str + String.fromCharCode(code); 15 }, ""); 16} 17 18function charCodeListToStringSplitFor(list) { 19 var str = ""; 20 for (var i = 0, len = list.length; i < len; i++) { 21 str += String.fromCharCode(list[i]); 22 } 23 return str; 24} 25 26function charCodeListToStringSlice(list, sliceSize) { 27 var str = ""; 28 for (var i = 0, len = list.length; i < len; i += sliceSize) { 29 var slicedList = list.slice(i, i + sliceSize); 30 str += String.fromCharCode.apply(null, slicedList); 31 } 32 return str; 33} 34 35function checkConvert(str) { 36 var list = stringToCharCodeList(str); 37 var convertedStr = charCodeListToString(list); 38 var splitConvertedStr = charCodeListToStringSplit(list); 39 var splitForConvertedStr = charCodeListToStringSplitFor(list); 40 var sliceConvertedStr = charCodeListToStringSlice(list, 8); 41 console.log(str + 42 "\n list: [" + list + "]" + 43 "\n bulk: " + convertedStr + 44 "\n split: " + splitConvertedStr + 45 "\n spfor: " + splitForConvertedStr + 46 "\n slice: " + sliceConvertedStr); 47} 48 49checkConvert("Hello, World!"); 50checkConvert("こんにちは、世界!"); 51checkConvert("昨日、近所の????野家行ったんです。????野家。"); 52checkConvert("????帰ったら????くれ");
charCodeListToStringSplit()
が一個一個処理するバージョン、charCodeListToStringSplitFor
はfor
を使った別実装、charCodeListToStringSlice()
は指定のサイズにまとめて処理するバージョンです。どちらも正常に動くことが確認できると思います。なお、"????"や"????"のようなU+10000以上になるためサロゲートペアで構成される文字が含まれる場合、途中不正な文字列が生成されることに注意してください。その後結合すれば問題はありません。
では、パフォーマンスはどうなのかです。ということでベンチマークテストを作りました。Benchmark.jsを入れてから試して見てください。
"use strict"; var Benchmark = require('benchmark') function charCodeListToString(list) { return String.fromCharCode.apply(null, list); } function charCodeListToStringSplit(list) { return list.reduce(function(str, code) { return str + String.fromCharCode(code); }, ""); } function charCodeListToStringSplitFor(list) { var str = ""; for (var i = 0, len = list.length; i < len; i++) { str += String.fromCharCode(list[i]); } return str; } function charCodeListToStringSlice(list, sliceSize) { var str = ""; for (var i = 0, len = list.length; i < len; i += sliceSize) { var slicedList = list.slice(i, i + sliceSize); str += String.fromCharCode.apply(null, slicedList); } return str; } var maxCharCode = 65535 // 2**16 - 1 var listSize = 32767; var list = []; for (var i = 0; i < listSize; i++) { list.push(Math.floor(Math.random() * (maxCharCode + 1))); } var suite = new Benchmark.Suite; suite .add("Bulk", function() { charCodeListToString(list); }) .add("Split", function() { charCodeListToStringSplit(list); }) .add("Split For", function() { charCodeListToStringSplitFor(list); }) .add("Slice 1", function() { charCodeListToStringSlice(list, 1); }) .add("Slice 8", function() { charCodeListToStringSlice(list, 8); }) .add("Slice 64", function() { charCodeListToStringSlice(list, 64); }) .add("Slice 256", function() { charCodeListToStringSlice(list, 256); }) .add("Slice 1024", function() { charCodeListToStringSlice(list, 1024); }) .add("Slice 4096", function() { charCodeListToStringSlice(list, 4096); }) .add("Slice 16384", function() { charCodeListToStringSlice(list, 16384); }) .add("Slice 32767", function() { charCodeListToStringSlice(list, 32767); }) .on('cycle', function(event) { console.log(String(event.target)); }) .run({ 'async': true });
手元のNode.jsでは次の結果になりました。
Bulk x 7,640 ops/sec ±3.31% (79 runs sampled) Split x 505 ops/sec ±2.49% (76 runs sampled) Split For x 502 ops/sec ±2.55% (75 runs sampled) Slice 1 x 119 ops/sec ±2.77% (65 runs sampled) Slice 8 x 740 ops/sec ±2.92% (76 runs sampled) Slice 64 x 2,301 ops/sec ±2.49% (79 runs sampled) Slice 256 x 3,166 ops/sec ±2.06% (80 runs sampled) Slice 1024 x 3,461 ops/sec ±2.14% (80 runs sampled) Slice 4096 x 3,455 ops/sec ±2.13% (79 runs sampled) Slice 16384 x 3,392 ops/sec ±2.57% (77 runs sampled) Slice 32767 x 3,398 ops/sec ±1.97% (78 runs sampled)
ops/secの値が大きいほど高速です。一個一個処理する場合は、もともと1/10以下になるなどかなり低速です。また、まとめるサイズが大きいほど、速くなっていきますが、1024をこえたあたりからあまり変わらなくなります。安全面を見て、1024,2048,4096あたりにするのが良いのかも知れません。ただ、他のブラウザでは最適なところが異なる場合がありますので、ご注意ください。
投稿2017/09/22 23:16
編集2017/09/22 23:30総合スコア21735
0
ベストアンサー
この現象には詳しくありませんが、スタックオーバーフローと呼ばれる現象だと思います。
引数の数が多過ぎでスタック領域を使い尽くすケースは見つかりませんでしたが、それが理由であれば、一つずつ繰り返し処理をすれば、回避できると思います。
JavaScript
1var input = this.sampledata.map(String.fromCharCode).join('');
Re: terater さん
投稿2017/09/22 05:03
編集2017/09/22 05:04総合スコア18164
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。