Ajax + zakres zmiennych w JS.

Ajax + zakres zmiennych w JS.
MI
  • Rejestracja:ponad 15 lat
  • Ostatnio:prawie 9 lat
0

Witam!

Staram się rozkminić obsługę jquery.

jest sobie taki kod:

Kopiuj
var resp=0;
function test()
{
 $.post("../ajax/email.php", { email: sender.value}, function(response){resp=response;});
 alert(resp);
}

I teraz niezależnie od tego co by skrypt email.php nie zwrócił, to pojawia się w alercie "0", tak jakby w ogóle nie przypisał tego w funkcji reagującej na odpowiedź. Jak to doprowadzic do ładu tak, żebym miał dostęp do odpowiedzi spoza metody $.post? Nie zależy mi zeby zmienna resp była globalna, moze być lokalna w funkcji test

edytowany 2x, ostatnio: misiakufal
BS
  • Rejestracja:ponad 15 lat
  • Ostatnio:ponad 12 lat
0

Tu nie chodzi o zakres zmiennej, tylko asynchroniczność.

W JavaScripcie istnieje funkcyjny zakres widoczności zmiennej. Tj. zmienna zadeklarowana w funkcji f() będzie widoczna w całym jej obrębie (również w zagnieżdżonych funkcjach). I tyle jest w JavaScripcie do powiedzenia o zasięgu.

U Ciebie zmienna resp jest globalna (zadeklarowana "w funkcji globalnej", tj. poza jakąkolwiek funkcją) i jest widoczna wewnątrz test. Tyle że w momencie wykonania alert() wciąż ma wartość zero.

Szkopuł w tym, że funkcja $.post() jest asynchroniczna. Znaczy to, że jej wywołanie tylko inicjalizuje jakąś akcję, która jest wykonywana i kończona później, "w tle". Już po tym, jak sama funkcja $.post() się zakończy i sterowanie przejdzie do kolejnej funkcji, czyli u Ciebie alert().

Funkcja post() musi być asynchroniczna, bo śle na serwer żądanie ajaxowe (gdy "AJAX" był jeszcze skrótem, litera "A" oznaczała asynchroniczność). Można też powiedzieć, że funkcja post() jest "nieblokująca": rozpoczyna jakąś akcję (tj. śle żądanie ajaxowe), ale nie czeka na jej zakończenie, tylko zwraca sterowanie, cobyś mógł odpalić sobie jeszcze jakieś inne funkcje zanim akcja się zakończy, tj. zanim serwer zwróci odpowiedź.

To skąd masz u licha wiedzieć, kiedy asynchroniczna akcja się zakończy, czyli tutaj: kiedy przyjdzie odpowiedź z serwera? Ano dzięki ostatniemu parametrowi post(). Jest to funkcja. Takie funkcje nazwamy callbackami (po polsku: funkcjami wywołania zwrotnego :) :) ). Funkcja $.post() gwarantuje, że Twój callback zostanie wykonany po przyjściu odpowiedzi z serwera. I otrzyma za parametr treść tej odpowiedzi. Czyli: Twoja funkcja callbackowa, w której ustawiasz zmienną resp zostanie wywołana dopiero po przyjściu odpowiedzi ajaxowej.

Jeszcze raz, działa to tak:
0. Gdzieś globalnie ustawiasz zmienną resp na zero.

  1. Wywołujesz $.post(). Funkcja ta rozpoczyna procedurę wysyłania żądania ajaxowego na serwer, ale nie czeka na zakończenie tego żądania, tj. na przyjście odpowiedzi. Funkcja natychmiast się kończy, ale obiecuje, że w przyszłości, gdy z serwera przyjdzie odpowiedź, wywoła Twój callback, w którym ustawiasz zmienną resp na response.
    !!! Zauważ, że Twój callback w kroku #1 NIE został wywołany.
  2. Wywołujesz funkcję alert(), wyświetlając wartość zmiennej resp resp. Wartość zmiennej się nie zmieniła -- wciąż siedzi tam zero.
    (po paru sekundach, lub raczej iluś milisekundach)
  3. Z serwera przychodzi odpowiedź.
  4. Zgodnie z obietnicą, jaka dała funkcja $.post(), wywoływany jest Twój callback. Jako pierwszy argument, który nazwałeś sobie response, callback dostaje treść odpowiedzi. Ustawiasz zmienną resp na tę treść.
    !!! Zauważ, że nie wyświetlasz już nigdzie wartości zmiennej resp. Zrobiłeś to już dawno, gdy odpowiedź jeszcze nie przyszła i gdy w zmiennej resp siedziało zero.

Lek na Twoje problemy? Wyświetl wartość zmiennej resp wewnątrz callbacka, na jego końcu (wtedy równie dobrze możesz wyświetlić wartość zmiennej response). W ogóle, cokolwiek nie chcesz zrobić z odpowiedzią, musisz to zrobić wewnątrz callbacka. Oczywiście, możesz też gdzieś z boku zdefiniować sobie funkcję np. handleResponse(res), a wewnątrz callbacka umieścić wywołanie handleRespone(response).

Czemu to jest takie dzikie z tymi wywołaniami asynchronicznymi? Czemu to tak skomplikowane? Cóż... tak naprawdę to to jest bardzo proste. To normalne programowanie wielowątkowe jest turbo-szalenie skomplikowane i bardzo trudno nie popełnić w nim błędu. W JavaScripcie, dzięki tzw. pętli zdarzeń i jej konsekwencji -- wywołaniom asynchronicznym i callbackom -- NIE DA SIĘ doprowadzić do całej klasy błędów, z którymi normalnie trzeba się użerać w programowaniu wielowątkowym. Podpowiem, że Ty z poziomu kodu tego nie widzisz, ale żądanie ajaxowe może sobie iść w osobnym wątku. Dzięki asynchroniczności, Twój kod nie jest blokowany na czas trwania żądania, a jednocześnie nie musisz się martwić kolejnością wykonywania operacji wewnątrz jakiegoś bloku kodu / funkcji. W JavaScripcie wykonanie Twojego bloku kodu NIGDY nie zostanie przerwane przez jakieś inne bloki kodu.

KR
  • Rejestracja:prawie 16 lat
  • Ostatnio:6 miesięcy
  • Postów:2514
0

$.post wykonuje się asynchronicznie, co oznacza, że przypisanie resp=response wykona się jakiś czas po zakończeniu funkcji test. zobacz sobie:

Kopiuj
var resp=0;
function test()
{
 alert('1');
 $.post("../ajax/email.php", { email: sender.value}, function(response){alert('3');resp=response;});
 alert('2');
 alert(resp);
}

wg. mnie tego alerta powinieneś wywołać w callbacku


░█░█░█░█░█░█░█░█░█░█░█░
MI
  • Rejestracja:ponad 15 lat
  • Ostatnio:prawie 9 lat
0

bswierczynski
biczuję się i wyznaczam sobie chłostę :/ W ogóle nie pomyslałem że to leci w osobnym wątku, baaa w ogóle nie pomyślałem ze JS jako język skryptowy może obsługiwać wątki :) ale to by się zgadzało. Problem polega na tym, ze w jednej funkcji potrzebuję wywołać parę razy AJAXa, i właśnie chciałem to sobie jeden po drugim załatwić a potem po wszystkich przeanalizować wszystkie odpowiedzi na raz. A tak to chyba będę musiał to robić kaskadowo.

krwq
No własnie na przykładzie wiem ze powinienem to wrzucic do ciała funkcji function(response){..} tylko ze powiedzmy, że funkcja test() wywołuje AJAXa 3 razy a potem w zależnosci od wszystkich 3 odpowiezi wykonuje pewne operacje.

KR
nie jest powiedziane, że to się wykonuje w osobnym wątku. równie dobrze silnik może poczekać aż skończy się wykonywać funkcja test i wtedy to wywołać synchronicznie, to w 100% zależy od implementacji. pewne jest jedynie to, że żadne dwie funkcje (w sensie sam kod JS) nie będą się wykonywać jednocześnie
KR
  • Rejestracja:prawie 16 lat
  • Ostatnio:6 miesięcy
  • Postów:2514
0

możesz zawsze zrobić coś takiego:

Kopiuj
function test(clb)
{
  // jakieś operacje
  $.post("../ajax/email.php", { email: sender.value}, function(response)
    {
      // jakies operacje, np.: response = JSON.parse(response);
      clb(response); // tutaj moze byc cokolwiek w parametrze
      // jakies operacje
    });
  // jakies operacje
}

// wywołanie np. tak:
test(function(r) {alert(r);}); 

░█░█░█░█░█░█░█░█░█░█░█░
edytowany 1x, ostatnio: krwq
0
misiakufal napisał(a):

W ogóle nie pomyslałem że to leci w osobnym wątku, baaa w ogóle nie pomyślałem ze JS jako język skryptowy może obsługiwać wątki :) ale to by się zgadzało.

Zdecydowana większość języków skryptowych posiada obsługę wątków, zauważalne wyjątki stanowią PHP (w końcu to tylko przekombinowany język szablonów) i JS właśnie. @bswierczynski nie wyraził się może dostatecznie jasno, JavaScript technicznie jest jednowątkowy, pracuje w oparciu o kolejkę zdarzeń, w danym momencie wykonuje się tylko jeden blok kodu, kiedy on się kończy to kolejny handler zostaje wyciągnięty z kolejki i odpalony. Całą asynchroniczność JS można streścić w krótkim "wykonaj potem".

MI
  • Rejestracja:ponad 15 lat
  • Ostatnio:prawie 9 lat
0

hmm... no już czaję, cóż, trzeba będzie robić kaskadowo:/ dzieki za zainteresowanie:)

PS. Jednak postanowiłem wszystko zebrać do jednego skryptu i wywołać jeden skrypt z większą ilością parametrów po prostu:)

edytowany 2x, ostatnio: misiakufal
BS
  • Rejestracja:ponad 15 lat
  • Ostatnio:ponad 12 lat
0

@misiakufal:
Chodzi o to, że z poziomu JavaScriptu wątków nie widzisz (odłóżmy na chwilę bajery w stylu WebWorkery) i nie musisz się nimi martwić. Jednak implementacja silnika JavaScript, np. silnik przeglądarki, MOŻE niektóre z Twoich operacji wykonywać wielowątkowo.

W przypadku NodeJS-a tak właśnie jest. Niektóre rzeczy, takie jak operacje dostępu do dysku czy zapytania do bazy danych, wykonują się w osobnych wątkach. Cały ciężar zarządzania wielowątkowością spoczywa jednak na silniku JavaScriptowym (tzw. środowisku wykonawczym). To programiści owego silnika muszą się napocić i martwić, żeby nic im się z tymi wątkami nie pokaszaniło. Ty tylko mówisz, że tu chcesz coś odczytać z dysku, tu coś posłać do bazy danych, a tam wysłać asynchroniczne żądanie. Środowisko wykonawcze niektóre lub wszystkie z tych rzeczy może sobie wykonać w osobnych wątkach -- tak, by było najwygodniej/najszybciej.

@krwq pisał, że nie jest powiedziane, iż żądanie ajaxowe faktycznie wykona się w osobnym wątku. To prawda -- to zależy od implementacji. I, co więcej, nie powinno mieć wpływu na nasz kod. My tylko wiemy, że funkcje ajaxowe działają asynchronicznie i nie wolno nam polegać na tym, że będzie inaczej. Sprawdziłam na szybko eksperymentalnie jak to jest w nowoczesnej przeglądarce (akurat w Fx) i wyszło mi, że faktycznie nasza funkcja wykonuje się dalej, a w międzyczasie -- równolegle -- wysyłane jest żądanie.

@PS:
Nie do końca rozumiem o co chodzi w pierwszym zdaniu Twojej wypowiedzi. Fakt, sam język JS nie definiuje obsługi wielowątkowości. Ba, specyfikacja ES5 nie wspomina nawet o pętli zdarzeń (!). Fakt faktem, że implementacje pętlę zdarzeń mają i że programiści JS przyzwyczajeni są do codziennego korzystania z wywołań asynchronicznych. I że to wszystko razem pozwala środowisku wykonawczemu na bardzo efektywne i fundamentalnie bezpieczne korzystanie z wielowątkowości. Z punktu widzenia programisty jest to całkowicie automatyczne.

Wg mnie to ciekawy sposób na wielowątkowość. NodeJS pokazuje, że w niektórych warunkach wydajność jest naprawdę spora -- również dlatego, że środowisko wykonawcze nie spawnuje nie wiadomo ilu wątków (w szczególności: ich liczba nie musi zależeć od liczby requestów) -- a programista wciąż nie musi zaprzątać sobie głowy standardowymi problemami charakterystycznymi dla programowania współbieżnego.

edit:
@misiakufal:
A co do kaskadowości -- nie wiem, czy musisz z niej tu korzystać. Jeśli nie zależy Ci na tym, by żądania wysyłać po kolei, a jedynie na tym, by przetworzyć odpowiedzi gdy już wszystkie przyjdą, to możesz puścić wszystkie N żądań równolegle. A po odbiorze każdej odpowiedzi możesz zapisać ją np. w tablicy oraz zinkrementować sobie jakiś licznik otrzymaneŻądania. Kiedy otrzymaneŻądania będzie równe N, możesz przetworzyć wszystkie odpowiedzi.

edytowany 1x, ostatnio: bswierczynski
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)