web-dev-qa-db-ja.com

一部のモバイルブラウザでのHTML5Canvasのパフォーマンスの問題。

こんにちは私はスマートフォンとデスクトップブラウザの両方で同様に実行できるはずのWebアプリを持っています。私はiPhoneのような小さなデバイスで奇妙な動作をすることを期待していましたが、私ができるAndroidデバイスであるAndroidギャラクシータブでうまく動作することをかなり確信していました現時点ででテストを実行します。

今、私は物事をテストするためにギャラクシータブにたくさんのブラウザをインストールしました:

  • Androidネイティブブラウザ
  • Chrome for Android
  • Firefox for Android

私が使用したデスクトップで

  • Firefox
  • グーグルクローム

そして最後に私はテストするiPhoneを持っています。

このWebサイトでは、ピクセルとスプライトベースの描画にHTML5キャンバスを使用しており、派手な変換、フィルター、効果はなく、ほとんどが単純なパスとポリゴンです。私はタッチイベントをリッスンし、適切な再描画のためにrequestAnimationFrameを使用します。

全体的に、アプリケーションはデスクトップブラウザで正常に動作し、iOS Safari(iPhone)およびFirefox-on-Androidでも正常に動作します。それでも、Androids NativeBrowserは私に問題を与えています。 javascriptが応答しないときに画面が赤く点滅し、画面に触れるとほとんど常に点滅するように設定しました。

ですから、AndroidネイティブアプリとHTML5に既知の問題があるかどうか疑問に思います。ネイティブブラウザの名前が存在しないため、これに関する情報をグーグルで検索するのは非常に困難です。 詳細情報を入手できるアイデアはありますか?ネイティブのAndroidブラウザの遅延の原因となる可能性のあるアイデアはありますか?

この問題についていくつかのアイデアがあります。

  • iOSはrequestAnimationFrameをサポートしていないため、タイムアウトベースの置換に置き換えました。 Androidのネイティブブラウザでその代替品を使用すると、問題は解決しません。

  • 私はAJAX(google clojure xhrio)を定期的に使用して、サーバーからデータを取得しています。データ取得コールバックがイベントパイプラインを詰まらせている可能性がありますか?

  • ログコンソールメッセージ(console.log)は、アプリケーションの速度を低下させることがわかっていますか?ブラウザをトリガーして、DOMツリーまたは関連するものを再実行できますか?

14
wirrbel

私は多くのブラウザでcanvasを使ってたくさんの実験をしました。私が気付いたいくつかのパフォーマンスの問題:

まず、あなたの推測について:

  • requestAnimationFrameがブラウザでサポートされている場合、描画やアプリ自体の応答性が向上します。フォールバックは常に可能ですが、タイミングに注意する必要があるため、setTimeoutまたはsetIntervalを使用してください。この ロバストなpolyfill は少し役立つかもしれませんが、ネイティブのrequestAnimationFrameと比較して何もありません。

  • Console.logがフレームごとに(またはほぼ)呼び出されると、パフォーマンスが低下します。ネイティブAndroidブラウザにはコンソールオブジェクトがないため、ブラウザが呼び出されるたびにエラーが生成され、アプリケーションの速度が低下します。次の操作を実行できます。

    if(typeof console === "undefined"){ console = {}; }

  • 強力なリアルタイムアプリケーションの場合 Webソケット はhttpリクエストよりも高速です。残念ながら、この機能は古いネイティブAndroidブラウザではサポートされていません。Webソケットを使用できない場合は、httpリクエストを最小限に抑える必要があります。

注: Chrome for Android requestAnimationFramewebsocketsなど、ここで引用したHTML5機能のほとんどをサポートしています。

詳しくは:

  • コンテキスト2dfillTextを使用してテキストを描画するのはコストがかかりすぎますが、一部のブラウザではさらに悪化します。テキストを別のキャンバスに事前レンダリングするか、ビットマップフォントを使用します。 (ネイティブAndroidブラウザーでは、事前レンダリング用にfilltext描画を置き換えた後、私が作成した一部のゲームでパフォーマンスが10〜15 FPSから30〜45FPSに向上しました。 )。

  • パフォーマンスの低下も引き起こすため、コンテキストのスケーリングと回転は避けてください。スプライトを1回だけスケーリングまたは回転する必要がある場合は、事前レンダリングを使用します。

  • リアルタイムの描画を最小限に抑える必要があります。できる限り、事前にレンダリングしてください。変更され、更新が必要なものだけを再描画します。

  • メモリ効率 およびガベージコレクタに適したコードを記述してみてください。

やるべきことはもっとたくさんあります。いくつか引用しました。

ヒント:パフォーマンスキラーであるかどうかわからない機能のストレステストをいくつか行い、ベンチマーク結果を取得します。

モバイルアプリケーション、特にリアルタイムアプリでは、最適化が過剰であるか、メモリが少し増えるだけであれば、すべての最適化は問題ありません。

詳細については、以下のリンクをたどってください。

投稿とチュートリアル でパフォーマンスも検索してください。

[〜#〜]編集[〜#〜]
この jsfiddleコードスニペット は、この回答でカバーされているいくつかのものを示し、ベンチマークに対する大まかなfpsカウンターを提供します。このフィドルを自分で編集してチェックしてください。

42

描画する内容に応じて、Html5キャンバスで最も一般的なパフォーマンス向上戦略は、レイヤー(つまり、複数のキャンバス)を利用し、各アニメーションフレームで全体を再描画するのではなく、再描画が必要なレイヤーのみを更新することです。このようなものを自分でロールすることも、 http://www.concretejs.com/ のようなものを使用することもできます。これは、ヒット検出、階層化、キャッシングなどの周辺機能を可能にする軽量のHtml5キャンバスフレームワークです。ピクセル比のサポート、ダウンロードなど。次のようにします。

var wrapper = new Concrete.Wrapper({
  width: 500,
  height: 300,
  container: el
});

var layer1 = new Concrete.Layer();
var layer2 = new Concrete.Layer();

wrapper.add(layer1).add(layer2);

// something happens which requires you to redraw layer2, but not layer1...
layer2.sceneCanvas.context.fillStyle = 'red';
layer2.sceneCanvas.context.fillRect(0, 0, 200, 100);
0
Eric Rowell