Mozilla Hacks: API selektorów w DOM w Firefoksie 3.5

W ramach serii tłumaczeń artykułów z bloga Mozilla Hacks, przedstawiam dzisiaj tłumaczenie artykułu DOM Selectors API in Firefox 3.5 autorstwa Johna Resiga. Oryginalny artykuł i jego tłumaczenie dostępne są na warunkach licencji Creative Commons Attribution 3.0 USA.

API selektorów w DOM w Firefoksie 3.5

Specyfikacja Selectors API, rekomendacja W3C, to nowe rozwiązanie pozwalające programistom JavaScriptu odnajdywać elementy drzewa DOM strony przy użyciu selektorów CSS. To pojedyncze API pozwala na przeszukiwanie drzewa DOM i odnajdywanie jego elementów przy użyciu prostego, ujednoliconego interfejsu.

API selektorów jest jednym z lepiej obsługiwanych przez wszystkie przeglądarki nowych standardów: można z niego korzystać już dziś w Internet Explorerze 8, Chrome, Safari, Firefoksie 3.5 i wkrótce w Operze 10.

Korzystanie z querySelectorAll

Selectors API zawiera dwie metody dostępne na wszystkich dokumentach, elementach i fragmentach DOM: querySelector i querySelectorAll. Metody te działają prawie identycznie – obie przyjmują jako argument selektor CSS i zwracają pasujące do niego elementy DOM (z tą różnica, że querySelector zwraca tylko pierwszy pasujący element).

Na przykład, mając dany poniższy fragment kodu HTML:

<div id="id" class="class">
    <p>Pierwszy akapit.</p>

    <p>Drugi akapit.</p>
</div>

możemy wykorzystać querySelectorAll do ustawienia czerwonego koloru tła wszystkich akapitów leżących wewnątrz diva o ID równym „id”:

var p = document.querySelectorAll("#id p");

for ( var i = 0; i < p.length; i++ ) {

    p[i].style.backgroundColor = "red";
}

Możemy też odnaleźć pierwszy akapit diva o klasie „class” i ustawić jego nazwę klasy na „first”.

document.querySelector("div.class > p:first-child")
    .className = "first";

Dotychczas, bez użycia Selectors API, tego rodzaju przeszukiwanie wymagałoby napisania długiego kodu JavaScript/DOM, złożonego z wielu linii i wielu zapytań.

O ile metody Selectors API są relatywnie proste w użyciu (pobierają tylko jeden argument), o tyle bardziej problematyczną sprawą jest dobór selektorów CSS. API selektorów korzysta z selektorów CSS natywnie obsługiwanych przez przeglądarkę do stylowania elementów przy użyciu CSS. W większości przeglądarek (Firefoksa, Safari, Chrome i Opery) oznacza to, że możemy w pełni korzystać z selektorów CSS 3. Internet Explorer 8 obsługuje bardziej ograniczony podzbiór selektorów, włączając w to selektory CSS 2 (które i tak są bardzo przydatne).

Największym wyzwaniem dla nowych użytkowników API selektorów jest więc określenie, które selektory CSS są odpowiednie do odnalezienia pożądanych elementów – szczególnie, że większość programistów piszących kod działający w wielu przeglądarkach ma doświadczenie głównie z ograniczonym podzbiorem w pełni działających selektorów CSS 1.

Dobrze jest zacząć od specyfikacji selektorów CSS 2 i CSS 3, ale warto też przejrzeć poniższe artykuły, by dowiedzieć się więcej (w języku angielskim – przyp. tłum.):

Implementacje w bibliotekach

Najciekawszy przypadek użycia API selektorów to nie tyle ich bezpośrednie stosowanie przez programistów WWW, ale ich wykorzystanie w bibliotekach, które już teraz dostarczają funkcjonalność selektorów CSS w DOM. Istotnym dziś problemem w szerszym stosowaniu API selektorów jest fakt, że nie są one dostępne we wszystkich przeglądarkach, dla których tworzy się obecnie strony (w tym IE 6, IE 7 i Firefox 3). Dlatego też, dopóki starsze przeglądarki są w użyciu, musimy korzystać z narzędzia pośredniczącego, aby odtworzyć zachowanie selektorów CSS w DOM.

Na szczęście w wielu istniejących bibliotekach jest dostępne API zgodne z Selectors API (w rzeczywistości Selectors API zostało w dużej mierze zainspirowane przez istniejące biblioteki). Co więcej, wiele z tych implementacji używa wewnętrznie właśnie Selectors API. Oznacza to, że można stosować selektory CSS w DOM w wielu przeglądarkach już teraz, zapewniając większą wydajność w nowych przeglądarkach obsługujących Selectors API, bez nadmiernego wysiłku.

Oto niektóre z istniejących implementacji, które korzystają z Selectors API, o ile to możliwe:

Warto jeszcze raz podkreślić duży skok w wydajności, jaki powoduje korzystanie z nowego API (w porównaniu z tradycyną mieszanką DOM i JabaScriptu, stosowaną do tej pory). Różnicę tę widać na przykład we wzroście wydajności bibliotek javascriptowych, odkąd zaimplementowały one Selectors API.

Ostatnio wykonane testy przyniosły następujące wyniki:

Widać tu dramatyczny wzrost wydajności po zaimplementowaniu natywnego API selektorów w bibliotekach – całkiem możliwe, że podobny wzrost wydajności zobaczysz także w swoich aplikacjach.

Zestaw testów

Razem ze specyfikacją Selectors API przygotowany został zbiór testów Selectors API, jego autorem jest John Resig z Mozilli. Ten zbiór testów pozwala określić jakość implementacji API selektorów w głównych przeglądarkach.

Aktualne wyniki (w momencie pisania oryginalnego artykułu – przyp. tłum.) dla przeglądarek obsługujących nowe API:

  • Firefox 3.5: 99.3%
  • Safari 4: 99.3%
  • Chrome 2: 99.3%
  • Opera 10b1: 97.5%
  • Internet Explorer 8: 47.4%

Internet Explorer 8, jak wspomniano wcześniej, nie obsługuje większości selektorów CSS 3, dlatego nie przechodzi większości powiązanych testów.

Selectors API pozwala na proste i szybkie odnajdywanie elementów DOM strony. Już teraz przynosi ono pożytek osobom korzystającym z bibliotek javascriptowych zapewniających podobną funkcjonalność, dlatego też zachęcamy do wypróbowania nowego API już teraz.

Mozilla Hacks: Nieprzezroczystość w Firefoksie 3.5

W ramach serii tłumaczeń artykułów z bloga Mozilla Hacks, przedstawiam dzisiaj tłumaczenie (króciutkiego) artykułu Opacity in Firefox 3.5, autorstwa Chrisa Blizzarda. Oryginalny artykuł i jego tłumaczenie dostępne są na warunkach licencji Creative Commons Attribution 3.0 USA.

Nieprzezroczystość w Firefoksie 3.5

To będzie bardzo krótka notka, ale warta opublikowania, bo pokazuje, jak możliwości przeglądarek rozwijają się, począwszy od własnej implementacji producenta po w pełni wspierany standard.

Firefox 3.5 nie obsługuje już specyficznej dla Mozilli własności CSS -moz-opacity. Programiści chcący określić stopień nieprzezroczystości elementu powinni stosować standardową własność opacity.

Własność opacity pojawiła się już w Firefoksie 0.9, a -moz-opacity została oznaczona jako przestarzała. W Firefoksie 3.5 została ostatecznie usunięta.

Trwało to długo, jak na prostą własność, ale warto o tym wspomnieć, by pokazać perspektywę czasową dla tego rodzaju funkcji i ich związku ze standardami.

Mozilla Hacks: Korzystanie z Web Workers

W ramach serii tłumaczeń artykułów z bloga Mozilla Hacks, przedstawiam dzisiaj tłumaczenie artykułu Using Web Workers – Working Smarter, Not Harder. Oryginalny artykuł i jego tłumaczenie dostępne są na warunkach licencji Creative Commons Attribution 3.0 USA.


Korzystanie z Web Workers – jak pracować mądrze, a nie ciężko

Autorem tego artykułu jest Malte Ubl, który wykonał sporo dobrej roboty przy użyciu technologii Web Workers w ramach projektu bespin.

W ostatnim czasie aplikacje webowe stały się znacznie bogatsze. Programy działające w przeglądarce, takie jak GMail, Meebo i Bespin pokazują nam, jak WWW będzie wyglądać i zachowywać się w przyszłości. Kluczowym aspektem tworzenia przyjaznej dla użytkownika aplikacji jest wysoka responsywność. Użytkownicy nie lubią czekać, a szczególnie nie lubią sytuacji, w których wydaje się, że program działa, po czym przestaje reagować.

W sercu współczesnych aplikacji WWW po stronie klienta leży język programowania JavaScript. JavaScript wraz z obiektowym modelem dokumentu DOM jest całkowicie jednowątkowy. Oznacza to, że w JavaScripcie tylko jedna rzecz może się zdarzyć w danej chwili. Nawet jeśli komputer ma 32-rdzeniowy procesor, tylko jeden rdzeń będzie zajęty podczas długich obliczeń. Na przykład, obliczając idealną trajektorię lotu na Księżyc nie można jednocześnie renderować animacji, która pokazuje trajektorię w tym samym czasie i nie ma możliwości reagowania na zdarzenia użytkownika, takie jak kliknięcia myszą czy pisanie na klawiaturze podczas obliczeń.

Współbieżność

Dla zachowania responsywności podczas intensywnych obliczeń większość współczesnych języków programowania wykorzystuje współbieżność. W przeszłości do uzyskania współbieżności często wykorzystywano wątki. Klasyczne wątki utrudniają jednakże programiście zrozumienie przebiegu programu, co często prowadzi do trudnych do zrozumienia błędów i chaotycznego zachowania w chwili, gdy różne wątki próbują równocześnie operować na tych samych danych.

Technologia wątków roboczych – Web Workers – zalecana przez WHATWG, pojawiła się w Firefoksie 3.5, pozwalając na wzbogacenie programów w JavaScripcie o współbieżność, unikając problemów związanych z typowymi programami wielowątkowymi. Rozpoczęcie wątku roboczego jest bardzo proste – wystarczy użyć konstruktora new Worker.

W tym przykładzie plik worker.js zostanie wczytany i uruchomiony w nowym wątku, dla niego utworzonym.

// Utwórz wątek roboczy na bazie pliku "worker.js"
var worker = new Worker("worker.js");

Komunikacja między głównym wątkiem interfejsu użytkownika a wątkami roboczymi opiera się na przesyłaniu komunikatów przy użyciu metody postMessage. Metoda ta została dodana do Firefoksa 3 by zapewnić komunikację między oknami. Aby przesłać komunikat z wątku roboczego do strony, wystarczy użyć tej metody:

// Wyślij komunikat do głównego wątku UI
postMessage("Witaj, strono!");

Aby odebrać wiadomość od wątku roboczego, na obiekcie typu Worker należy określić procedurę obsługi zdarzenia “onmessage”. Tutaj po prostu wyświetlimy dane zdarzenia, przekazane do tej procedury. W naszym przypadku własność “event.data” zawiera tekst “Witaj, strono!”, przesłany powyżej.

worker.onmessage = function (event) {

  alert(event.data);
  // Wyślij wiadomość do wątku roboczego
  worker.postMessage("Witaj, wątku!");

}

Do wysłania komunikatów do wątku roboczego wywołujemy metodę postMessage na obiekcie wątku. Aby odebrać te komunikaty w wątku, należy zdefiniować funkcję onmessage, która będzie wywoływana po każdym przesłaniu do niego komunikatu.

Obsługa błędów

Istnieją dwa sposoby obsługi błędów czasu wykonania w wątku. Po pierwsze, wewnątrz wątku można zdefiniować funkcję onerror. Po drugie, można obsłużyć błędy z zewnątrz wątku, przypisując procedurę onerror obiektowi typu Worker:

worker.onerror = function (event) {

  alert(event.message);
  event.preventDefault();
}

Metoda event.preventDefault() zapobiega wykonaniu domyślnej operacji, którą byłoby tutaj wyświetlenie błędu użytkownikowi lub wypisanie jej w konsoli błędów. Zamiast tego, w tym miejscu wyświetlmy treść błędu w oknie powiadomienia.

Brak współdzielenia

Wątki robocze nie dzielą żadnych stanów ze stroną, z którą są powiązane, ani z żadnymi innymi wątkami roboczymi; jedyną możliwą interakcją jest przesyłanie komunikatów przy użyciu metody postMessage. Wątki robocze nie mają dostępu do DOM, nie mogą więc manipulować stroną WWW. W ten sposób nie ma żadnego ryzyka dla integralności danych w sytuacji, gdy wiele wątków chce równocześnie operować na tych samych danych.

Typowe wykorzystanie wątków roboczych składa się ze strony-komponentu JavaScript, oczekującej na zdarzenia użytkownika. Kiedy nastąpi zdarzenie wywołujące intensywne obliczenia, do wątku roboczego przesyłany jest komunikat, który powoduje rozpoczęcie obliczeń. Skrypt na stronie może jednak natychmiast powrócić do oczekiwania na dalsze zdarzenia. W momencie, gdy wątek roboczy skończy pracę, przesyła wiadomość do strony, która może wówczas np. wyświetlić wyniki.

nigdy-wiecej
Ostrzeżenie przed nieresponsywnym skryptem, wyświetlane przez przeglądarki, gdy skrypt wykonuje się zbyt długo, odchodzi w przeszłość dzięki wątkom roboczym.

Przykład – ciąg Fibonacciego

W kolejnym przykładzie wątek roboczy oblicza w tle liczby Fibonacciego od 0 do 99. W rzeczywistości, ponieważ obliczanie liczb Fibonacciego tą nieefektywną
metodą może trwać długo przy większych liczbach (np. większych niż 30), skrypt może nawet nigdy nie zakończyć się na komputerze (albo „wyłożyć sie” z powodu przepełnienia stosu), ale ponieważ dzieje się to w wątku roboczym, nie ma to żadnego skutku co do responsywności strony. Można więc nadal wyświetlać skomplikowaną animację, by uprzyjemnić oczekiwanie na kolejną liczbę.

Poniższa strona HTML zawiera skrypt uruchamiający wątek roboczy z pliku „fib-worker.js”. Komunikaty z wątku roboczego wyświetlane są w konsoli przeglądarki (czy raczej Firebuga – przyp. tłum.) przy użyciu console.log.

<!DOCTYPE html>
<html>
    <head>
      <title>Web Worker API Demo</title>
      <script type="text/javascript">

        var worker = new Worker("fib-worker.js");
        worker.onmessage = function (event) {
          console.log(event.data.index +" -> " + event.data.value)
        }
      </script>  
    </head>
    <body>
    </body>

</html>

Plik JavaScript z implementacją wątku roboczego zawiera pętlę, która wylicza liczby Fibonacciego i przesyła wyniki do strony.

// Plik fib-worker.js
function fib(n) {

   return n < 2 ? n : fib(n-1) + fib(n-2);

}
 
for(var i = 0; i < 100; ++i) {

   postMessage({
      index: i,
      value: fib(i)

   })
}

W powyższym przykładzie widać też, że przy użyciu postMessage można przesyłać złożone obiekty. Obiekty takie mogą zawierać wszystko to, co można przesłać w formacie JSON. Oznacza to, że nie można przesłać funkcji, a obiekty przekazywane są przez wartość, a nie przez referencję.

API wątków roboczych

Wątki robocze obsługują funkcję o nazwie importScripts. Dzięki niej można wczytać do wątku roboczego więcej plików źródłowych.

importScripts("file.js");

importScripts("foo.js", "bar.js");

Jeśli funkcja zostanie wywołana z wieloma argumentami, skrypty zostaną pobrane równolegle, ale wykonane w kolejności zdefiniowania. Funkcja ta jest blokująca – bieg wątku zostanie wstrzymany do momentu pobrania i wykonania wszystkich skryptów.

W kolejnym przykładzie wczytujemy zewnętrzny plik JavaScript, który oblicza wartość funkcji SHA-1 z ciągów znaków, a następnie wykorzystujemy go do wyliczania wartości SHA-1 dla zawartości odczytanej poprzez żądanie AJAX. Używamy tu standardowego obiektu XMLHttpRequest do pobrania zawartości z adresu URL przekazanego do zdarzenia onmessage. Co ciekawe, nie musimy budować tutaj asynchronicznego żądania AJAX, jako że wątek sam w sobie jest asynchroniczny względem strony, tak więc oczekiwanie na żądanie HTTP nie jest tu żadnym problemem.

importScripts("sha1.js")
 
function onmessage(event) {
    var xhr = new XMLHttpRequest();

    xhr.open('GET', event.data, false);
    xhr.send();

    postMessage(sha1(xhr.responseText));
}

Inne API dostępne dla wątków roboczych

Wątki mogą używać XMLHttpRequest do żądań AJAX, jak w powyższym przykładzie, jak również mają dostęp do bazy danych po stronie klienta dzięki API Web Storage. API te w wątkach roboczych są takie same jak w „zwykłym” JavaScripcie.

Funkcje setTimeout i setInterval (oraz clearTimeout i clearInterval) są dostępne, co pozwala na wykonywanie kodu po upływie danego czasu lub co pewien interwał. Dostępny jest też obiekt navigator object, udostępniający informacje o przeglądarce.

Dodatkowe API mogą zostać dodane w przyszłości.

Zgodność z przeglądarkami

W momencie pisania tego artykułu, o ile wiadomo jego autorowi, tylko Firefox 3.5 obsługuje możliwość przesyłania złożonych obiektów poprzez postMessage i implementuje rozszerzone API opisane powyżej. Safari 4 zawiera prostą implementację API Worker. W innych przeglądarkach można korzystać z Workers poprzez wtyczkę Google Gears, w której technologia ta pojawiła się na początku.

Przykład wykorzystania na prawdziwej stronie

W ramach projektu Bespin, opartego na przeglądarce edytora kodu źródłowego, z powodzeniem wykorzystujemy wątki robocze do implementacji intensywnych dla procesora funkcji, takich jak sprawdzanie poprawności kodu na bieżąco czy podpowiadanie kodu. Stworzyliśmy także nakładkę, implementującą API Worker w ramach Google Gears, która także dodaje brakującą funkcjonalność w Safari 4, a także umożliwiliśmy korzystanie ze transparentnych zdarzeń własnych, na bazie interfejsu postMessage. Komponenty te zostaną upublicznione jako odrębna biblioteka, do wykorzystania przez inne projekty.

Technologia Web Workers odgrywa istotną rolę w próbie uczynienia z Otwartej Sieci WWW jeszcze potężniejszej platformy dla złożonych programów. Jako że wszystko, co robią wątki robocze, to wykonywanie JavaScriptu, łatwo jest napisać skrypty, które działają także w przeglądarkach nie zapewniających luksusu wątków roboczych. Polecamy dodanie Web Workers do Twoich programów, aby stały się bardziej responsywne i przyjemniejsze w użyciu.

Mozilla Firefox 3.5 już jest!

Przed paroma minutami, po roku wytężonych prac, Mozilla oficjalnie wydała wersję 3.5 przeglądarki internetowej Firefox.

Jak dla mnie najfajniejsze są dwie rzeczy: nowy, lepszy silnik JavaScriptu (w tym wątki “web workers” i natywny JSON) oraz obsługa znaczników <audio> i <video> i formatu Ogg. Obsługa filtrów w SVG i transformacje w CSS także ucieszą wielu web developerów. A dla zwykłego użytkownika ważne jest to, że w 3.5 aplikacje WWW działają szybciej i otworem stoi droga do zwiększenia ich możliwości.

Więcej informacji na stronie Możliwości Firefoksa 3.5 i w informacjach o wydaniu.

Zapraszamy do pobierania i życzymy miłego użytkowania! :)

PS. Na bieżąco aktualizowane statystyki pobierania Firefoksa 3.5 można podglądać na stronie downloadstats.mozilla.com.

Mozilla Hacks: Natywny JSON – większe bezpieczeństwo i wydajność

Mozilla Hacks to zbiór artykułów na temat nowych możliwości silnika Gecko w Firefoksie 3.5. Członkowie Aviary.pl zamierzają tłumaczyć co ciekawsze artykuły z Mozilla Hacks na polski. Na Techblogu zacznę od artykułu „Better security and performance with native JSON”, autorstwa Aruna Ranganathana. Oryginalny artykuł i jego tłumaczenie dostępne są na warunkach licencji Creative Commons Attribution 3.0 USA.


Większe bezpieczeństwo i wydajność dzięki natywnej obsłudze formatu JSON

Mechanizm reprezentacji danych JavaScript Object Notation (JSON) szybko stał się nieodzownym narzędziem programisty WWW, umożliwiając aplikacjom w języku JavaScript pobranie i przetworzenie danych w sposób intuicyjny, w skryptach, z prostą hermetyzacją danych. Firefox 3.5 zawiera natywną obsługę JSON-a, udostępnioną przez własność window.JSON obiektu globalnego.

Natywny JSON, wbudowany w maszynę wirtualną JS, stał się możliwy dzięki specyfikacji ECMAScript 5 (specyfikacja w formacie PDF), której inne części również zostały
zaimplementowane w Firefoksie 3.5. Obecnie natywną obsługę JSON-a udostępniają Firefox 3.5 i IE8, można się też spodziewać, że i inne przeglądarki wkrótce będą miały ją zaimplementowaną.

Natywna obsługa formatu JSON ma dwie zalety:

  1. Bezpieczeństwo. Korzystanie z funkcji eval do wyznaczenia wartości wyrażeń zwróconych jako ciągi znaków nie jest bezpieczne. Ponadto, natywny JSON obsługuje wyłącznie dane. Nie można go użyć do przetworzenia obiektów zawierających wywołania metod – spowoduje to zgłoszenie błędu.
  2. Wydajność. Przetwarzanie JSON-a przy użyciu zewnętrznych skryptów i bibliotek jest zwykle znacznie wolniejsze niż natywne przetwarzanie JSON-a przez przeglądarkę.

Oto kilka przykładów.

API JSON do wyszukiwania może wyglądać jak poniżej:

/* 
Załóżmy, że dane w zmiennej data
zostały otrzymane z serwera.
Dla przejrzystości, wyświetlamy
je tutaj w osobnych liniach.
*/
 
var data = ' { "responseData":
{"results": [
    {
        "SafeSearch":"true",
        "url":"http://www.arunranga.com/i.jpg",
    },
    {
        "SafeSearch":"false",
	 "url":"http://www.badarunranga.com/evil.jpg",
    }
]}}';

Takie zasoby mogły zostać zwrócone na przykład przez proste żądanie HTTP GET z wykorzystaniem API typu REST.

Dzięki natywnemu JSON-owi, można napisać taki kod:

/*
 Pobranie uchwytu do ww. zasobu JSON.
 Najwygodniej zrobić to za pomocą
 zewnętrznych bibliotek obsługujących
 natywnego JSON-a.
*/
 
if (window.JSON) {

    var searchObj = JSON.parse(data);
    for (var i=0; i++; i < searchObj.responseData.results.length) {

        if (searchObj.responseData.results[i].SafeSearch) {

            var img = new Image();
            img.src = searchObj.responseData.results[i].url;

            // ... Wstaw obrazek do drzewa DOM ...
    }
}

Dzięki metodzie stringify można obiekt z powrotem zserializować (przekształcić do ciągu znaków w formacie JSON – przyp. tłum.):

// Powrót do wyjściowej sytuacji

 
var data = JSON.stringify(searchObj);
 
// zmienna 'data' zawiera teraz pierwotny ciąg znaków

Oczywiście, aby w pełni skorzystać z możliwości JSON-a, warto spróbować pobierać dane JSON z innych domen, poprzez mechanizmy callback takie jak JSONP. (JSONP nie skorzysta z natywnego JSON-a, nie wiem, czemu artykuł oryginalny o nim tu wspomina – przyp. tłum.). Wielu programistów raczej nie będzie korzystać z obiektu JSON bezpośrednio. Najczęściej korzystać oni będą z mechanizmów udostępnianych przez biblioteki takie jak Dojo i jQuery. Biblioteki te ułatwiają odbieranie i przetwarzanie zasobów JSON z różnych domen i udostępniają wiele “cukru składniowego” dla procesu wywołań callback i manipulacji drzewem DOM.

Natywna implementacja JSON-a współpracuje z popularną biblioteką json2.js (która prawidłowo rozpoznaje, czy dostępna jest natywna obsługa JSON-a), dzięki czemu programiści mogą bez problemu korzystać z przetwarzania JSON-a w przeglądarkach bez natywnej jego obsługi (API zdefiniowane w json2.js jest identyczne z natywnym API omawianym w tym artykule – przyp. tłum.). W chwili pisania tego artykułu, Dojo i jQuery ogłosiły, że będą wspierać natywną obsługę JSON-a: