chevron-left chevron-right

Piotr Nalepa Frontend, architektura i AI

[JS] Wykrywanie wydajności urządzeń mobilnych za pomocą HTML5 i JS

Ta wersja
blog.piotrnalepa.pl/2014/12/09/js-wykrywanie-wydajnosci-urzadzen-mobilnych-za-pomoca-html5-i-js
Opublikowano
Autor
, Staff Software Engineer
Kategoria
JavaScript
Uwagi
Napisz do mnie · Napisz na X

Ten wpis ma 11 lat. Od tego czasu przeglądarki i narzędzia mogły się zmienić, więc zanim użyjesz kodu, sprawdź go z aktualną dokumentacją.

Projektując nowoczesne interfejsy użytkownika strony internetowej, aż się prosi aby dodawać małe subtelne animacje elementów znajdujących się na stronie, aby zwiększyć przyjemność korzystania z interfejsu. Lecz takie podejście może mieć ogromny wpływ na płynność działania strony.

Jednym ze sposobów na ograniczenie liczby efektów może być wykrywanie wielkości ekranu, tym samym zakładając że urządzenie mobilne (w przypadku ekranu o małej rozdzielczości) nie będzie wystarczająco mocne aby uciągnąć wszystkie efekty. Takie podejście już teraz może być błędne, ze wzgędu na to, że urządzenia już teraz mogą mieć duże ekrany, nie posiadając wymaganej mocy obliczeniowej. W przyszłości może również dojść do sytuacji, że urządzenia mobilne będą dorównywały mocą laptopom i większość z nich będzie posiadało ekrany o dużej rozdzielczości, tj. powyżej 1024x768px.

Na szczęście istnieje inny sposób na wykrycie wydajności danego urządzenia. W tym celu wykorzystałem element <canvas/> oraz requestAnimationFrame API a do zebrania danych wykorzystałem Google Analytics API.

Sekcja 1Mechanizm sprawdzenia wydajności

Przykładowy kod HTML, który stanowi bazę dla naszego mechanizmu sprawdzenia wydajności urządzenia mobilnego wygląda następująco:

Przykład 1JavaScript
1
<canvas id="board" width="300" height="300"></canvas>

Jest to element o wymiarach 300 pikseli na 300 pikseli. Następnie trzeba sprawdzić, czy requestAnimationFrame API jest dostępne w przeglądarce:

Przykład 2JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
window.requestAnimFrame = (function () {
  return  window.requestAnimationFrame        ||
          window.webkitRequestAnimationFrame  ||
          window.mozRequestAnimationFrame     ||
          window.oRequestAnimationFrame       ||
          window.msRequestAnimationFrame      ||
          function (callback, element) {
            window.setTimeout(function () {
                callback(+new Date);
            }, 1000 / 60);
          };
})();

Z racji tego, że API w każdej przeglądarce może mieć inną nazwę (z dodanym prefiksem), to trzeba kod ujednolicić dla ułatwienia.

Mając już tak przygotowaną bazę, możemy przystąpić do pisania kodu odpowiedzialnego za wykonanie pomiaru i przesłanie wyniku za pomocą Google Analytics.

Przykład 3JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
(function (window, document, undefined) {
  var isAnimationRunning  = true;
  var isResultDisplayed   = false;
  var oldtime       = +new Date;
  var fps           = 0;
  var checkCount    = 0;
  var maxCheckCount = 100;
  var results  = [];
 
  var showScore = function (score) {
    var boardCanvas   = document.getElementById('board');
    var boardContext  = boardCanvas.getContext('2d');
    var boardWidth    = boardCanvas.width;
    var boardHeight   = boardCanvas.height;
 
    boardContext.clearRect(0, 0, boardWidth, boardHeight);
    boardContext.fillStyle = '#000000';
    boardContext.font      = 'normal 1rem Arial';
    boardContext.fillText(score + ' fps', 10, 26);
  };
 
  var checkLoop = function (time) {
    time = parseInt(time, 10);
 
    if (!isNaN(time)) {
      fps     = parseInt(1000 / (time - oldtime), 10);
      oldtime = time;
    }
 
    if (isAnimationRunning &amp;&amp; checkCount &lt; maxCheckCount) {
      checkCount++;
      results.push(fps);
      requestAnimFrame(checkLoop);
    } else {
      if (!isResultDisplayed) {
        var sum = results.reduce(function (a, b) {
          return a + b;
        }, 0);
        var score = sum / maxCheckCount;
 
        isResultDisplayed = true;
        ga('send', 'event', 'performance', 'result', navigator.userAgent, score);
        showScore(score);
      }
      requestAnimFrame(checkLoop);
    }
  }
 
  checkLoop();
 
})(this, this.document);

Zdefiniowałem dwie funkcje checkLoop() oraz showScore(). Pierwsza z nich uruchamia pętlę, która zbiera pomiary czasu do tablicy results. Po wykonaniu wymaganej liczby powtórzeń pomiaru - maxCheckCount, następuje sprawdzenie czy wynik został wyświetlony. Jeśli nie, to następuje wyliczenie średniej z zebranych wyników i wyświetlenie jej na stronie oraz wysłanie zdarzenia do Google Analytics z danymi dotyczącymi wyniku oraz rodzaju przeglądarki.

Eksperyment można wzbogacić za pomocą dodania dodatkowego elementu <canvas/>, która będzie wykonywała zaawansowaną animację, np. animację zegarka.

Sekcja 2Wyniki pomiarów

Na podstawie zebranych wyników (51 niezależnych pomiarów - różnych urządzeń mobilnych) mogłem wywnioskować, że im nowsze urządzenie mobilne tym lepiej sobie radzi z obsługą animacji. Najgorszy wynik miały Blackberry Bold 9900 - 14,61fps (frame per second), Samsung i5510 - 14,32fps oraz Nokia Lumia 710 - 31fps.

Zauważyłem jeszcze jedną rzecz, że przeglądarki internetowe (nie ważne czy na urządzeniach mobilnych czy też na standardowym komputerze) mają górne ograniczenie liczby FPS i średnie wyniki oscylują w okolicach 60fps. Większość urządzeń jednak ma wydajność na poziomie między 50fps a 60fps.

Sekcja 3Podsumowanie

Tego typu funkcjonalność można wykorzystać, aby sprawdzić czy dane urządzenie w danym momencie jest w stanie uruchomić zaawansowane animacje po stronie interfejsu. Jeśli na przykład użytkownik ma kilka programów uruchomionych w tle, np. gry i akurat chce przejrzeć wiadomości na stronie internetowej, to wtedy warto sprawdzić czy przeglądarka będzie w stanie płynnie wyświetlić zaawansowane animacje na naszej stronie. Żaden użytkownik nie będzie lubił gdy przewinięcie w dół lub przełączenie się między widokami danych będzie trwało długo lub będzie jeszcze bardziej spowalniało urządzenie.

Co myślisz o tego typu rozwiązaniu? Zapraszam do komentowania.

Udostępnij
Uwagi

O autorze

Staff Software Engineer

Piszę na tym blogu od 2009 roku, a strony i aplikacje webowe tworzę zawodowo od 14 lat. Obecnie w Bishop Fox prowadzę frontend platformy Cosmos, od samego początku projektu. Wcześniej pracowałem m.in. w OLX, KUDO, Auto1 i eZ Systems. Piszę tu o tym, czego nauczyłem się w praktyce: o JavaScripcie, TypeScripcie, Reakcie, CSS-ie i architekturze frontendu. Występowałem też jako prelegent na konferencjach w Polsce i Europie. Masz pytanie albo pomysł na wpis? Daj znać!