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.
- 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.
- 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)
- Z serwera przychodzi odpowiedź.
- 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.