ホームページ  >  記事  >  ウェブフロントエンド  >  jQuery 同期 Ajax によって引き起こされる UI スレッド ブロック問題の解決策

jQuery 同期 Ajax によって引き起こされる UI スレッド ブロック問題の解決策

黄舟
黄舟オリジナル
2017-08-13 10:09:142095ブラウズ

この記事では、jQuery 同期 Ajax によって引き起こされる UI スレッドのブロック問題とその解決策を主に紹介します。興味がある方は、ぜひ学習してください。今日は自殺しましたが、同期された Ajax によって引き起こされる UI スレッドのブロック問題に遭遇しました。

その理由は、コードの再利用性を向上させるために、さまざまなパラメーターを受け取り、データを取得することのみを担う getData という関数をカプセル化したためです。データ。取り除かれた基本ロジックは次のとおりです。

function getData1(){
    var result;
    $.ajax({
      url : 'p.php',
      async : false,
      success: function(data){
        result = data;
      }
    });

  return result;
}

ここでの ajax は非同期にすることができません。そうでない場合、関数が返されたときに結果に値が割り当てられていないため、エラーが発生します。そこで、async:falseを追加しました。問題はないようです。この関数を呼び出すと正常にデータを取得できます。

$('.btn1').click(function(){
    var data = getData1();
    alert(data);
});

次に、別の関数を追加したいと思います。ajax リクエストには一定の時間がかかるため、リクエストを行う前にページに読み込み効果を与える必要があります。つまり、「読み込み中」の gif を表示する必要があります。おそらく誰もが見たことがあるでしょう。したがって、私の処理関数は次のようになります:

$('.btn1').click(function(){
    $('.loadingicon').show();
    var data = getData1();
    $('.loadingicon').hide();
    alert(data);
});

リクエストの前に読み込み画像を表示し、リクエストが完了した後は非表示にします。問題はないようです。効果を明確に確認するために、次のように p.php コードを 3 秒間スリープさせました:

<?php
sleep(3);
echo (&#39;aaaaaa&#39;);
?>

しかし、実行時に問題が発生し、ボタンをクリックしたときに読み込み画像が期待どおりに表示されませんでした。 . ページの反応はどうでしたか?長い間トラブルシューティングを行った結果、原因が async:false であることがわかりました。

ブラウザのレンダリング (UI) スレッドと js スレッドは相互に排他的であり、時間のかかる js 操作を実行すると、ページのレンダリングがブロックされます。非同期 ajax を実行する場合は問題ありませんが、同期リクエストに設定すると、他のアクション (ajax 関数の背後にあるコードとレンダリング スレッド) が停止します。リクエストが開始される前の文に DOM 操作ステートメントが含まれている場合でも、この同期リクエストは実行時間を与えずに UI スレッドを「すぐに」ブロックします。これがコードが失敗する理由です。

setTimeout はブロックの問題を解決します

問題の場所がわかったので、解決策を見つけてみましょう。同期ajaxリクエストがスレッドをブロックしないようにするには、setTimeoutを考え、sestTimeoutにリクエストコードを入れて、ブラウザがスレッドを再起動して動作できるようにすれば問題は解決するのではないでしょうか?それ以来、私のコードは次のようになりました:

$(&#39;.btn2&#39;).click(function(){
    $(&#39;.loadingicon&#39;).show();
    setTimeout(function(){
      $.ajax({
        url : &#39;p.php&#39;,
        async : false,
        success: function(data){
          $(&#39;.loadingicon&#39;).hide();
          alert(data);
        }
      });
    }, 0);
});

setTimeout の 2 番目のパラメーターは 0 に設定され、ブラウザーは設定された最小時間の後にそれを実行します。何はともあれ、まずは実行して確認しましょう。

読み込み中の画像が表示されますが! ! !画像が動かないのはなぜですか? それは明らかにアニメーション GIF です。この時点で、同期リクエストは遅延したものの、実行中に UI スレッドがブロックされるだろうとすぐに思いました。このブロッキングは非常に優れており、gif画像さえも動かず、静止画像のように見えます。

結論は明白です。setTimeout は症状を治療しますが、根本的な原因は治療しません。これは、同期リクエストを「わずかに」非同期にするのと同じであり、その後も同期の悪夢に陥り、スレッドがブロックされます。計画は失敗した。

Deferred を使用する時期です

バージョン 1.5 以降、jQuery には Deferred オブジェクトが導入されました。これは、非常に便利な汎用非同期メカニズムを提供します。詳細については、この記事 http://www.jb51.net/article/54762.htm を参照してください。

そこで、次のように Deferred オブジェクトを使用してコードを書き直しました:

function getData3(){
    var defer = $.Deferred();
    $.ajax({
      url : &#39;p.php&#39;,
      //async : false,
      success: function(data){
        defer.resolve(data)
      }
    });
    return defer.promise();
}  

$(&#39;.btn3&#39;).click(function(){
    $(&#39;.loadingicon&#39;).show();
    $.when(getData3()).done(function(data){
      $(&#39;.loadingicon&#39;).hide();
      alert(data);
    });
});

ajax リクエストの async:false を削除したことがわかります。これは、このリクエストが再び非同期であることを意味します。さらに、success 関数の次の文に注意してください: defer.resolve(data) Deferred オブジェクトの replace メソッドは、任意の型のパラメーターを渡すことができます。このパラメータはdoneメソッドで取得できるため、非同期でリクエストしたデータをこの方法で返すことができます。

この時点で、問題は解決されました。遅延オブジェクトは非常に強力で便利なので、活用できます。

私のテスト コードはすべて次のとおりです。興味のある学生はテストに使用できます:

<button class="btn1">async:false</button>
<button class="btn2">setTimeout</button>
<button class="btn3">deferred</button>
  
<img class="loadingicon" style="position:fixed;left:50%;top:50%;margin-left:-16px;margin-top:-16px;display:none;" src="loading2.gif" alt="正在加载" />
<script>

  function getData1(){
    var result;
    $.ajax({
      url : &#39;p.php&#39;,
      async : false,
      success: function(data){
        result = data;
      }
    });

    return result;
  }

  $(&#39;.btn1&#39;).click(function(){
    $(&#39;.loadingicon&#39;).show();
    var data = getData1();
    $(&#39;.loadingicon&#39;).hide();
    alert(data);
  });


  
  $(&#39;.btn2&#39;).click(function(){
    $(&#39;.loadingicon&#39;).show();
    setTimeout(function(){
      $.ajax({
        url : &#39;p.php&#39;,
        async : false,
        success: function(data){
          $(&#39;.loadingicon&#39;).hide();
          alert(data);
        }
      });
    }, 0);
  });



  function getData3(){
    var defer = $.Deferred();
    $.ajax({
      url : &#39;p.php&#39;,
      //async : false,
      success: function(data){
        defer.resolve(data)
      }
    });
    return defer.promise();
  }  

  $(&#39;.btn3&#39;).click(function(){
    $(&#39;.loadingicon&#39;).show();
    $.when(getData3()).done(function(data){
      $(&#39;.loadingicon&#39;).hide();
      alert(data);
    });
  });</script>

PS: Firefox は最適化されていますか?

上記の問題は Chrome と IE9 でテストされており、結論は一貫しています。しかし、Firefox でテストしたところ、同期された ajax は UI スレッドをブロックしませんでした。つまり、この問題はまったく存在しません。他のコードでテストしてみましたが、Firefox では、js スレッドが UI スレッドをブロックすることに疑いの余地はありません。考えられる推測の 1 つは、Firefox が同期 ajax を最適化しているということですが、実際のところはまだわかりません。知っている人がいたらアドバイスをお願いします。

以上がjQuery 同期 Ajax によって引き起こされる UI スレッド ブロック問題の解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。