13

大量の画像を処理する必要があります。まず、画像のサイズが50x60より大きいかどうかを確認し、不良画像のカウンターを適切に増やす必要があります。

私が抱えている問題は、InternetExplorer8のn.width/の速度が非常に遅いことです。n.height確認n.offsetWidthn.clientWidthましたが、速度的にはすべて同じです。ただし、この値は、関心のあるタグにn.style.width常に設定されているとは限らないため、使用できません。<img />

次のコードを検討してください。

Javascript

var Test = {
    processImages: function () {
        var fS = new Date().getTime();

        var minimagew = 50,
            minimageh = 60;
        var imgs = document.getElementsByTagName('img');
        var len = imgs.length,
            isBad = 0,
            i = len;

        while (i--) {
            var n = imgs[i];

            var imgW = n.width;
            var imgH = n.height;

            if (imgW < minimagew || imgH < minimageh) {
                isBad++;
            }
        }

        var fE = new Date().getTime();
        var fD = (fE - fS);

        console.info('Processed ' + imgs.length + ' images in ' 
                     + fD + 'ms.  ' + isBad + ' were marked as bad.');
    }
};

HTML

<img src="http://nsidc.org/images/logo_nasa_42x35.gif" />
   [snip 9998 images]
<img src="http://nsidc.org/images/logo_nasa_42x35.gif" />

コードは、10kの画像を解析する次の出力を生成します(3つの異なるCtrl + F5)

  • FF:115msで10000枚の画像を処理しました。10000は不良としてマークされました。
  • FF:99msで10000枚の画像を処理しました。10000は不良としてマークされました。
  • FF:87msで10000枚の画像を処理しました。10000は不良としてマークされました。
  • IE8:206ミリ秒で10000枚の画像を処理しました。10000は不良としてマークされました。
  • IE8:204msで10000枚の画像を処理しました。10000は不良としてマークされました。
  • IE8:208ミリ秒で10000枚の画像を処理しました。10000は不良としてマークされました。

ご覧のとおり、FF 3.6のコードは、IE8で実行されたコードよりも2倍高速です。

問題が実際にブラウザのディメンションプロパティの速度に関連していることを証明するために、:n.widthn.height定数を変更すると、次のようになります。

 var imgW = 43;
 var imgH = 29;

次の結果が得られます。

  • FF:38msで10000枚の画像を処理しました。10000は不良としてマークされました。
  • FF:34msで10000枚の画像を処理しました。10000は不良としてマークされました。
  • FF:33msで10000枚の画像を処理しました。10000は不良としてマークされました。
  • IE8:18ミリ秒で10000枚の画像を処理しました。10000は不良としてマークされました。
  • IE8:22msで10000枚の画像を処理しました。10000は不良としてマークされました。
  • IE8:17ミリ秒で10000枚の画像を処理しました。10000は不良としてマークされました。

それは正しい!<img />ディメンションチェックをスキップすると( node.width/node.clientWidthなどを呼び出す)、IE8は実際にはFirefoxよりもパフォーマンスが優れています。

IEが画像のサイズをチェックするのになぜこれほど時間がかかるのか、そして最終的にこのチェックのパフォーマンスを改善する方法について何か考えがありますか?

4

6 に答える 6

8

あなたのコードはかなり基本的です。最適化できる唯一のことは、寸法をチェックする方法です。

if (n.width < minimagew || n.height < minimageh) {
  isBad++;
}

このようwidthに、画像の が間違っていると、heightにアクセスできなくなります。悪いwidth.

しかし、Web サイトの一部として実際に 10,000 枚の画像は必要ないと思います。この場合、要素Imageではなくオブジェクトをチェックできます。<img>

loop {
  var img = new Image();
  img.src = "http://nsidc.org/images/logo_nasa_42x35.gif";
}

これにより、コードは IE 8 で 2 倍、FF で 10 倍高速になります。

これらの変更を行うと、私のコンピューターで次の改善が行われました( demo ) :

FF: 200 ms ->  7 ms
IE:  80 ms -> 20 ms
于 2010-10-17T11:52:40.763 に答える
5

言い換えると、ブラウザAがブラウザBよりもまったく同じ処理を行うのに時間がかかる理由を尋ねます。

まあ、彼らは同じことをしません。あなたはあなたが起こりたいことをあなたのスクリプトに書きます、そしてあなたの選んだブラウザはそれを実現するために最善を尽くします、しかしあなたはそれがどのようにそれをするかについてほとんどまたは全く制御できません。

ブラウザは、物事のやり方についてさまざまな哲学を持つさまざまなチームによって作成されています。20-something-line-scriptは、ブラウザーのコードの記述方法とブラウザーの内部動作に応じて、ブラウザーAで10000 cpu-cycles、ブラウザーBで50000cpu-cyclesを必要とする可能性があります。

この場合、IE8がFFと比較して遅い理由を詳細に説明するには、何が起こっているのかを内部で調べる必要があります。IE8のソースコードは公開されていないため、そこを見ることができず、何が起こっているのかを説明するのに十分詳細なドキュメントがあるかどうかはわかりません。

代わりに、物事を行う方法に関する2つの異なる哲学が、同じ最終結果を生み出す時間にどのように大きく影響するかについての例を示します。注:これは例であり、現実の世界との類似点はまったくの偶然です。

何をすべきか:

  • 画像の寸法を取得します。

チームA:

  1. 指定されたソースからファイルをロードします
  2. 画像をメモリにデコード
  3. 画像の幅と高さを返す

それは何も悪いことではありませんか?画像の幅と高さを返します。チームはそれをより良くすることができますか?

チームB:

  1. ファイルの最初の1024バイトをメモリにロードします
  2. 画像形式を検出する
    • jpegですか?ヘッダーFFC0を取得し、幅と高さを保存します
    • pngですか?ヘッダーを見つけ、幅と高さを保存します
    • gifですか?ヘッダーを見つけ、幅と高さを保存します
  3. 画像の幅と高さを返す

彼らのコードは画像の幅と高さも返しますが、チームAが書いたコードよりも数桁速い別の方法でそれを行います。ファイルの先頭のみがメモリに読み込まれ、寸法が取得されます。画像をデコードせずにヘッダーから。帯域幅、メモリ、時間を節約します。

それで、どれが最高ですか?チームAまたはチームBのコード?両方のチームが10万枚の画像に対してコードを実行している間、少し考えてみてください。...時間がかかる場合があります...ああ、チームBはすでに終了しています。彼らは、画像の10%が50x60ピクセルより小さく、そのうちの3つを開くことができなかったと言います。では、チームAはどうですか?しばらく待たなければならないようです...一杯のコーヒーかもしれませんか?

【10分後】

チームBが最高のコードを書いたと思いますが、私は正しいですか、それとも私は正しいですか?

チームAによると、画像の8%は50x60ピクセルよりも小さかったとのことです。奇妙なことに、それはチームBが言ったことではありませんでした。チームAは、ファイルが破損しているため、画像の20%のサイズを取得できなかったとも述べています。それはチームBが何も言わなかったことです...

では、どのコードが最高だと思いましたか?

言語の誤りをお詫びします。英語は私の母国語ではありません。

于 2010-10-23T01:26:47.057 に答える
4

これはおそらくあなたが探しているものではありませんが、他の誰かに役立つ場合に備えて投稿します. ブラウザーの基本機能の速度を改善する方法はないため、実行中にループによってブラウザーがフリーズするのを防ぐことができます。これを行うには、チャンクでループを実行し、setTimeout を 0 の時間で使用して次のチャンクを開始します。これにより、基本的に、ブラウザは次のチャンクを呼び出す前に再描画し、他のアクションを実行できます。スクリプトの修正版は次のとおりです。

var Test = {
    processImages: function() {
        var fS = new Date().getTime();

        var minimagew = 50,
            minimageh = 60,
            stepSize = 1000;
        var imgs = document.getElementsByTagName('img');
        var len = imgs.length,
            isBad = 0,
            i = len,
            stopAt = len;

        var doStep = function() {
            stopAt -= stepSize;
            while (i >= stopAt && i--) {
                var n = imgs[i];

                var imgW = n.width;
                var imgH = n.height;

                if (imgW < minimagew || imgH < minimageh) {
                    isBad++;
                }
            }

            if (i > 0)
                setTimeout(doStep, 0);
            else {
                var fE = new Date().getTime();
                var fD = (fE - fS);

                console.info('Processed ' + imgs.length + ' images in '
                     + fD + 'ms.  ' + isBad + ' were marked as bad.');
            }
        }
        doStep();
    }
};

もちろん、これにより合計実行時間は長くなりますが、作業中にページを使用できるようにするために使用できる場合があります。

于 2010-10-19T21:10:22.763 に答える
1

私はあなたの質問に非常に興味を持っていましたが、残念ながらあなたのコードを最適化することはできませんでした. IE の実行で約 30 ~ 40 ミリ秒短縮できました (これは明らかに物理マシンの能力に依存します)。しかし、私はほぼすべてを試しました

[element].widthの代わりに試したこと。

  • [element].getBoundingClientRect()- 基本的に、これは高さと幅を 1 つで返します
  • document.elementFromPoint(x, y)- を使用してoffsetLeft + 50offsetTop + 60その時点の要素が現在の要素と異なるかどうかを判断できました。つまり、「悪い」イメージでした。

最終的に、これは私が思いついた時間 (30 ~ 40 ミリ秒) を少しだけ調整するものです。

注: IE 8 でのベストタイムは 171ms でした

編集済み - 以下のコードを変更して、あなたのやり方、私のやり方、および Jquery の使用を含めました。テストしてみてください。

<html>
<script src="http://code.jquery.com/jquery-1.4.2.js" type="text/javascript"></script>
<script type="text/javascript">
var TestYourWay = {
    processImages: function () {
        var fS = new Date().getTime();

        var minimagew = 50,
            minimageh = 60;
        var imgs = document.getElementsByTagName('img');
        var len = imgs.length,
            isBad = 0,
            i = len;

        while (i--) {
            var n = imgs[i];

            var imgW = n.width;
            var imgH = n.height;

            if (imgW < minimagew || imgH < minimageh) {
                isBad++;
            }
        }

        var fE = new Date().getTime();
        var fD = (fE - fS);

        alert('Processed ' + imgs.length + ' images in '
                     + fD + 'ms.  ' + isBad + ' were marked as bad.');
    }
};


var TestMyWay = {
    processImages: function () {
        var fS = new Date(),
        imgs = document.getElementsByTagName('img'),
        isBad = 0;
        for (var i = 0, img; img = imgs[i]; i++) {
            if (img.width  < 50 || img.height < 60) {
                isBad++;
            }
        }
        var fD = new Date() - fS;
        alert('Processed ' + i + ' images in ' + fD + 'ms.  ' + isBad + ' were marked as bad.');
    }
};

var TestJquery = {
    processImages: function () {
        var fS = new Date(),
        imgs = $('img'),
        isBad = 0;
        imgs.each(function () {

           if (this.width  < 50 || this.height < 60) {
                isBad++;
            }
        });
        var fD = new Date() - fS;
        alert('Processed ' + imgs.length + ' images in ' + fD + 'ms.  ' + isBad + ' were marked as bad.');
    }
};

</script>
<body>
     <button onclick="javascript:TestYourWay.processImages();" id="yourWay">Your Way</button>
     <button onclick="javascript:TestMyWay.processImages();" id="myWay">My Way</button>
     <button onclick="javascript:TestJquery.processImages();" id="myWay">jQuery Way</button>
     <img src="http://nsidc.org/images/logo_nasa_42x35.gif" />
     <!--Copy This image tag 10000 times -->
</body>
</html>

その他の注意事項:

IE 8 の JavaScript エンジンは、FireFox 3.6+、Safari、または Chrome ほど高速ではありません。Opera はスクリプト エンジンを改善しましたが、それでも FF、Safari、Chrome ほど高速ではありません。ただし、Opera は IE 8 よりも優れている点もありますが、遅い点もあります。また、IE 9 は今年後半または来年初めにリリースされる予定であり、JavaScript エンジンが改善されています。ここで私が言っていることの統計を見ることができます。

https://spreadsheets.google.com/pub?key=0AuWerG7Xqt-8dHBuU2pGMncwTENNNGlvNzFtaE5uX0E&hl=en&output=html

于 2010-10-18T20:44:44.837 に答える
0

画面上 (または document.body の下) の要素のレイアウト属性にアクセスすると、IE で読み取り専用アクセスを行った場合でも、レイアウト オーバーヘッド (ロック、リフローなど) が発生する場合があります。

私はテストしませんでしたが、このようなことを試すことができます。

    var done=i;
    while (i--) { 
        var img=new Image();
        img.onload=function(){
           if (this.width < minimagew || this.height < minimageh) { 
              isBad++;
           } 
           if(done--==0){ onComplete(); }
        };
        img.onerror=function(){ done--; }
        img.src=imgs[i].src;
    }

長いループを使用しないでください。GUIを遅くする

編集: document.getElementsByTagName は予想よりも遅くなります。静的配列ではなく、変更を反映する動的オブジェクトを返します (存在する場合)。要素を配列にコピーしてみると、他の DOM API との干渉によるパフォーマンスの低下を抑えることができます。

于 2010-10-22T02:23:33.890 に答える
0

私はこれを IE でテストしていませんが、ループから変数宣言を削除することはできます。ループ、また、先に進んでimgWandimgH割り当てをスキップして、オブジェクトのプロパティに直接アクセスすることもできます。これにより、if ステートメントのロジック チェックの他の部分を画像に対して実行する必要がないため、1 つのオブジェクトの逆参照を節約できます。幅に誤りがあります。

var Test = {
    processImages: function () {
        var fS = new Date().getTime();

        var minimagew = 50,
            minimageh = 60;
        var imgs = document.getElementsByTagName('img');
        var len = imgs.length,
            isBad = 0,
            i = len;

        /* this is the only part updated */
        while (i--) {
            if (imgs[i].width < minimagew || imgs[i].height < minimageh) {
                isBad++;
            }
        }
        /* ... 'till here */

        var fE = new Date().getTime();
        var fD = (fE - fS);

        console.info('Updated:  Processed ' + imgs.length + ' images in ' 
                     + fD + 'ms.  ' + isBad + ' were marked as bad.');
    }
    ,processImagesOriginal: function () { // for comparisson
        var fS = new Date().getTime();

        var minimagew = 50,
            minimageh = 60;
        var imgs = document.getElementsByTagName('img');
        var len = imgs.length,
            isBad = 0,
            i = len;

        while (i--) {
            var n = imgs[i];

            var imgW = n.width;
            var imgH = n.height;

            if (imgW < minimagew || imgH < minimageh) {
                isBad++;
            }
        }

        var fE = new Date().getTime();
        var fD = (fE - fS);

        console.info('Original: Processed ' + imgs.length + ' images in ' 
                     + fD + 'ms.  ' + isBad + ' were marked as bad.');
    }
};

//Original: Processed 10000 images in ~38ms. 10000 were marked as bad.
//Updated:  Processed 10000 images in ~23ms. 10000 were marked as bad.
于 2010-10-21T23:59:36.200 に答える