Piotr Koszuliński

Piotr Koszuliński JavaScript ninja

Temat: odswiezenie grafiki dopiero po jej pobraniu

Hej. JS ma zasięg funkcyjny i do tego zasięg statyczny (leksykalny). To drugie to tzw. closure - jedna z najpotężniejszych rzeczy w JS. Warto o nim wiedzieć, ale to trochę za dużo by się rozpisywać na ten temat tutaj :).

Napisałem ostatnio dwa artykuły na ten temat:
Co lepiej wiedzieć o JavaScriptcie cz.1. - typy zasięgu i domknięcia
Co lepiej wiedzieć o JavaScriptcie cz.2. - hoisting, deklaracje funkcji i wyrażenia funkcyjne
W szczególności pierwszy powinien Cię w tym wypadku zainteresować.Piotr Koszuliński edytował(a) ten post dnia 03.11.11 o godzinie 22:10
Piotr Koszuliński

Piotr Koszuliński JavaScript ninja

Temat: odswiezenie grafiki dopiero po jej pobraniu

Wojciech Mazurek:
img.onload = function() { $("#grafika13").attr('src', img.src); }

BTW. nie wiem czy to przeoczenie, czy specjalnie, ale w tej linii też dobrze byłoby postawić średnik. Bo jeśli przypadkiem zacząłbyś następną linię od nawiasu "(", to byś sobie wywołał tę funkcję od razu :) To tzw. ASI - automatic semicolon insertion, które w tym wypadku by akurat tego średnika nie postawiło i potraktowało to jako wywołanie. Zasady ASI są co prawda dość proste (choć widziałem takie przypadki, że naprawdę można się zdziwić) i dlatego niektórzy namawiają aby w ogóle nie stawiać średników... poza średnikami na _początku_ linii zaczynających się od "(" bądź "[". Masakra :P Dlatego wolę stawiać zawsze, ale na końcu.
Wojciech Mazurek

Wojciech Mazurek właściciel, PPHU
Neuron

Temat: odswiezenie grafiki dopiero po jej pobraniu

Piotr Koszuliński:
Hej. JS ma zasięg funkcyjny i do tego zasięg statyczny

Powiedz mi prosze dlaczego taka konstrukcja

var s='';

function Zapytaj( zapytanie )
{ $.get(zapytanie, function(data) {
s=data;
}
);
return s;
}

dziala OK

a po zadeklarowaniu zmiennej lokalnej

function Zapytaj( zapytanie )
{
var sx='';
$.get(zapytanie, function(data) {
sx=data;
}
);
return sx;
}

zawsze zwraca pusta wartosc ?

konto usunięte

Temat: odswiezenie grafiki dopiero po jej pobraniu

a jak zrobisz po prostu bez "var" przed sx (opcja druga ktora pokazales) ?

Napewno powinno dzialac jak zrobisz gdzies na gorze:
var sx;
by zdefiniowac tego vara jako globalnego.
W tym przypadku tez nie musisz juz robic return sx, mozesz go sobie przeciez przeczytac pozniej, bez returna funkcji.

a potem dalej:
function Zapytaj( zapytanie )
{
sx='';
$.get(zapytanie, function(data) {
sx=data;
}
);
return sx;
}
Piotr Koszuliński

Piotr Koszuliński JavaScript ninja

Temat: odswiezenie grafiki dopiero po jej pobraniu

Wojciech Mazurek:
zawsze zwraca pusta wartosc ?

Myślę, że żadna z metod nie działa tak jak myślisz :) Generalnie, nie obsługuje się asynchronicznych callbacków, ani tak jak próbowałeś, ani w sposób proponowany przez Andrzeja.

Zacznijmy od tego - jeśli nie czytałeś mojego artykułu o zasięgu i closure w JS, to przeczytaj :P Ten albo inny, jeśli mój jest za słaby :P. Wtedy będziesz wiedział, że kiedy definiujesz funkcję, która jest callbackiem dla "$.get" wewnątrz funkcji "Zapytaj", to ten callback zapamiętuje miejsce swojej definicji. Co rozumiemy przez "zapamiętuje"? Ma dostęp PRZEZ REFERENCJĘ do wszystkich zmiennych, które były dostępne w funkcji "Zapytaj". To jest właśnie closure (domknięcie - czyli "domykanie zasięgu"). To samo zresztą tyczy się funkcji "Zapytaj" - ona też zapamiętuje swój scope, którym w pierwszym przypadku jest m.in. zmienna "s".

Czyli w przypadku:
1) Zapytaj domyka "s". Callback domyka to co jest w Zapytaj, czyli też "s".
2) Zapytaj nic nie domyka, callback domyka "sx".

Idźmy dalej. Teraz równie ważna sprawa - $.get jest asynchroniczną metodą. Oznacza to, że po jego wykonaniu od raz wykonywany jest następujący kod. W tym wypadku zwracany jest "sx/s". Czyli Twoja funkcja Zapytaj zwraca pusty string.
Następnie, po chwili, pobierane są dane z serwera, wywoływany jest callback i on ustawia zmienną "sx/s". I teraz zależnie od przypadku:

1) jako że zmienna "s" była zadeklarowana w scopie najwyżej, to jest ona dostępna TERAZ w każdym innym miejscu tego scope'a. Dlatego jeśli w tym samym scopie masz zadeklarowaną np. metodę obsluzDane(), to ta metoda, jeśli wykonamy ją PO wykonaniu callbacka będzie miała dostęp do danych z serwera.
2) jako że zmienna "sx" zadeklarowana została wewnątrz scope'a funkcji Zapytaj, to tylko funkcje zadeklarowane wewnątrz tej funkcji mają do niej dostep. Czyli nasza obsluzDane() nie będzie widzieć tej zmiennej.

Jakie są sposoby z radzeniem sobie z asynchronicznymi wywołaniami?
1) w callbacku dla $.get() wykonuj funkcję obsługującą dane, której przekażesz te dane jako argument - sposób najbanalniejszy
2) jak w przypadku 1. - deklarujesz zmienną w takim scopie, by funkcje obsługujące te dane widziały tę zmienną i wykonujesz W CALLBACKU funkcję obsługującą dane (tym razem już bez argumentów
3) wykorzystujesz tzw. promise'y, dostępne w jQuery - http://api.jquery.com/deferred.promise/ i http://api.jquery.com/category/deferred-object/ pamiętając że $.get zwraca promise'a.

I kolejny raz autopromocja :P. Prowadziłem ostatnio szkolenie i później jeszcze prezentację na tematy związane z asynchronicznością w JS. Tu są slajdy - http://code42.pl/2011/10/09/moje-prezentacje-z-devmeet...

BTW. ZAWSZE używamy "var". Nie korzystaj nigdy z globalnych zmiennych w innym celu niż do definicji głównego API Twojej aplikacji (najlepiej jednego obiektu, typu window.app).Piotr Koszuliński edytował(a) ten post dnia 04.11.11 o godzinie 17:25
Wojciech Mazurek

Wojciech Mazurek właściciel, PPHU
Neuron

Temat: odswiezenie grafiki dopiero po jej pobraniu

Piotr Koszuliński:

Zacznijmy od tego - jeśli nie czytałeś mojego artykułu o zasięgu i closure w JS, to przeczytaj :P Ten albo inny, jeśli mój jest za słaby :P. Wtedy będziesz wiedział, że kiedy

Przejzalem tylko - brak mi jeszcze punktow odniesienai aby sie zn nim zmiezyc - js cwicze od kilkudziesiecu godzin a to za malo aby czytac cokolwiek ze zrozumieniem ;)
Następnie, po chwili, pobierane są dane z serwera, wywoływany jest callback i on ustawia zmienną "sx/s". I teraz zależnie od przypadku:

No i intuicyjnie wyczuwalem ze cos takiego sie dzieje.
Sprobowalem dac klika zapytan w jednym kodzie i sie dopiero zaczely jaja ;)
Myslalem ze mi sie odebierane dane "sklejaja" ale ich poprostu jeszcze nie ma ;)
Teraz dopiero zauwazylem ze prawidlowy wynik (przy jednym cyklicznym zapytaniu w kodzie) jest przesuniety o jeden cykl co wszytko mi wyjasnia i potwierdza kolegi slowa - kod uzywa poprzedniej wartosci - dlatego zmienna lokalna nie dziala ;(


Dlaczego na sile proboje zaczac od konca - czyli od ajaxa
otoz popelnilem kiedys taki projekt http://neuron.com.pl/hall2007.html
i chce go odswierzyc i przeniesc GUI calowicie do przegladarki.
Ale ....
HAll to projekt amatorski - zakladamy ze dostaje to do reki automatyk czy uczniak ktory i owszem ze zrobieniem prostych dokumentow html sobie poradzi ale z ambitnym kodem js juz nie musi.
Dlatego chce przygotowac bibloteke prostych klockow do montazu - chcialbym na koniec uzyskac np taka funkcje:
hall_switch_image(image_id, vbit, image_off, image_on) ktora to
sciagnie z serwera stan zmiennej binarnej vbit i zaleznie od jej wartosci podstawi do img o wskazanym id jeden ze wskazanych obrazkow.
Oczywiscie najpierw ladowanie do zmiennej a podmiana jak bedzie gotowe.

user definiuje jedna linie w sekcji script i jedna linie w kodzie html i ma..

No i widze tu powazny problem bo jak sie domyslam powinienem wyjac procedure data z obslugi $.GET i przekazac jej id grafiki i linki plikow aby sie wykonala po odebraniu danych z serwera, stworzyla tymczasowy obiekt image, zaldowala odpowiedni plik graficzny przeladowala go do (nastepna metoda w kaskadzie) wskazanej grafiki i popelnila samobujstwo niszczac tymczasowy obiekt image z dodatkami - w obiektpascalu opierajac sie na dynamicznie tworzonych objektach zrobilbym to w mojej "czytelni" olowkiem na rolce tego co w tej czytelni zawsze jest pod reka ale w js nie mam pojecia jak sie za to zabrac ;((((
Piotr Koszuliński

Piotr Koszuliński JavaScript ninja

Temat: odswiezenie grafiki dopiero po jej pobraniu

1) Pamiętaj, że w JS nie musisz czyścić pamięci. Więc "samobójstwo" obiektu Image nie jest Ci potrzebne. GC to wyczyści.
2) Jeśli masz ciąg wywołań asynchronicznych, to żeby nie zagłębiać się ciągle w kodzie funkcja w funkcji, to pomyśl własnie o tych promise'ach z jQuery. To nie jest banalna koncepcja, ale bardzo pomaga jak się ją zrozumie.
3) Generalnie... to co chcesz zrobić można w JS-ie zrobić bardzo ładnie, albo tragicznie :D JS niestety ma to do siebie, że nie zmusza do pisania choćby "sensownie". Jako że sam język mocno odbiega od większości innych, to trzeba się sporo dowiedzieć, bo go nie kaleczyć.
Wojciech Mazurek

Wojciech Mazurek właściciel, PPHU
Neuron

Temat: odswiezenie grafiki dopiero po jej pobraniu

Piotr Koszuliński:
Jako że sam język mocno odbiega od większości innych, to trzeba się sporo dowiedzieć, bo go nie kaleczyć.

No wlasnie sie czegos ciekawego ($%@%^#@) dowiedzialem ;(
Przygotowalem sobie procedurke - dzialala - poszedlem na kolacje wrocilem i nie dzialala.

$.Get - "Obiekt nie obsługuje tej właściwości lub metody"

Lukalem na kazda klamerke i nawiasik - nic nie znalazlem, zmienialem wersje jqery - bez rezultatu.
W koncu napisalem cala procke od nowa i dzia - porownalem ze stara i byla tylko jedna roznica:
$.Get i $.get jedna z*****a literka ....
Tylko czemu przedtem dzialalo ? A moze mi sie zdawalo....

Co do zagadnienia - postanowilem zrobic to troche inaczej. Poniewaz mam raptem 200 zmiennych ktore user moglby zastosowac w swoim kodzie to zrobilem sobie (na razie dla bitow) cos ala JSON - robie ciag 0010100110 a potem parsuje go przez s.charAt (tu tez sie nabralem na literce A - zastrzelilbym tego co zrobil taka specyfikacje jezyka)
Nie bede sciagal z serwera pojedynczych zmiennych wtedy kiedy sa potrzebne tylko caly czas, symultanicznie kompletny pakiet zmiennych - i tak to ma w 90% pracowac w lanie a nie internecie - 1kb na sekunde nikogo dzis nie zabije. Da to te elastycznosc ze user zero bedzie mial poprostu zmienne do uzycia nie zastanawiajac sie skad one sa. W druga strone nie powinno byc klopotow bo w delphianym serweze jestem w stanie zapanowac nad czasowa obsluga wszelkich zapytan

Generalnie jQery mi sie zaczyna podobac i jesli uda mi sie skonczyc projekt to chyba posle im jakas darowizne ;)
Ide spac bo sie jasno robi ;)
Piotr Koszuliński

Piotr Koszuliński JavaScript ninja

Temat: odswiezenie grafiki dopiero po jej pobraniu

Wojciech Mazurek:
Piotr Koszuliński:
Jako że sam język mocno odbiega od większości innych, to trzeba się sporo dowiedzieć, bo go nie kaleczyć.

No wlasnie sie czegos ciekawego ($%@%^#@) dowiedzialem ;(
Przygotowalem sobie procedurke - dzialala - poszedlem na kolacje wrocilem i nie dzialala.

$.Get - "Obiekt nie obsługuje tej właściwości lub metody"

Tylko czemu przedtem dzialalo ? A moze mi sie zdawalo....

Musiało Ci się zdawać. Nie mogło działać. To podstawowa i ŚWIETNA cecha JS - rozróżnia wielkość znaków.
I szczerze mówiąc nie wiem jak można na to narzekać i na to, że jest charAt, a nie charat. Taka konwencja została przyjęta i raz, że uważam że jest dobra, dwa że nie widzę żadnego argumentu przeciw.

Następna dyskusja:

to byl dopiero reset!!!




Wyślij zaproszenie do