{"id":218,"date":"2009-12-13T15:59:56","date_gmt":"2009-12-13T14:59:56","guid":{"rendered":"http:\/\/eriz.pcinside.pl\/weblog\/ajax-w-jquery-i-callbacki-javascript-218.html"},"modified":"2009-12-30T12:32:09","modified_gmt":"2009-12-30T11:32:09","slug":"ajax-w-jquery-i-callbacki-javascript","status":"publish","type":"post","link":"https:\/\/eriz.pcinside.pl\/weblog\/ajax-w-jquery-i-callbacki-javascript-218.html","title":{"rendered":"AJAX w jQuery i callbacki JavaScript"},"content":{"rendered":"<p>O tym, \u017ce jQuery jest niez\u0142ym narz\u0119dziem, nie trzeba nikogo przekonywa\u0107. Filozofia \u0142a\u0144cuchowania \u2013 mam na my\u015bli konstrukcj\u0119 \u2013 nie jest jednak taka oczywista w u\u017cytku pod ka\u017cdym wzgl\u0119dem. Z jQuery da si\u0119 wygodnie pracowa\u0107; to, \u017ce co\u015b nie wychodzi wcale nie oznacza, i\u017c trzeba od razu zmienia\u0107 u\u017cywanego frameworka.<\/p>\n<p>Wystarczy zrozumie\u0107 kilka rzeczy. <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_wink.png\" alt=\";)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> Notka jest przeznaczona dla raczej pocz\u0105tkuj\u0105cych; starzy wyjadacze pewnie niczego nowego si\u0119 nie dowiedz\u0105.<\/p>\n<p><!--more--><\/p>\n<h3>Spos\u00f3b przekazywania zdarze\u0144<\/h3>\n<p>Zacznijmy od tego, jak skonstruowana jest wi\u0119kszo\u015b\u0107 funkcji, kt\u00f3re pozwalaj\u0105 precyzowa\u0107 w\u0142asne zdarzenia. Jest to niejako spowodowane konstrukcj\u0105 samego j\u0119zyka. Przypomnijmy sobie dwie funkcje udost\u0119pniane przez przegl\u0105darki oraz spos\u00f3b podstawiania parametr\u00f3w. Mam tu na my\u015bli <em>setInterval<\/em> i <em>setTimeout<\/em>. Jeden z parametr\u00f3w, to czas; drugi \u2013 zmienna przechowuj\u0105ca funkcj\u0119.<\/p>\n<p>Tak, tak \u2013 je\u015bli do tej pory o tym nie wiedzia\u0142e\u015b(a\u015b) \u2013 w jQuery zmienna mo\u017ce by\u0107 funkcj\u0105 (r\u00f3wnie\u017c w innych j\u0119zykach mo\u017cemy spotka\u0107 tego typu konstrukcje). Tak samo podpina si\u0119 zdarzenia dla r\u00f3\u017cnych obiekt\u00f3w, ale teraz wracam do tematu. <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_wink.png\" alt=\";)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<h3>Callbacki w praktyce<\/h3>\n<p><em>Callback<\/em> jest to \u2013 innymi s\u0142owy \u2013 funkcja uruchamiana przez jQuery\/przegl\u0105dark\u0119, gdy jest wywo\u0142ywane okre\u015blone zdarzenie. I tutaj kluczowa uwaga \u2013 funkcja ta jest wywo\u0142ywana <strong>asynchronicznie<\/strong> \u2013 czyli niezale\u017cnie od tych wykonywanych w dalszym ci\u0105gu skryptu.<\/p>\n<p>Wr\u00f3\u0107my jeszcze do przyk\u0142adu z <em>setTimeout<\/em>:<\/p>\n<p><code lang=\"javascript\">setTimeout(function(){ alert('testujemy!') }, 5000);<br \/>\nalert('a wczesniej?');<\/code><\/p>\n<p>Jak my\u015blisz, co poka\u017ce przegl\u0105darka jako pierwsze? <em>Testujemy<\/em>, a zaraz po nim <em>a wcze\u015bniej?<\/em> Ot\u00f3\u017c nie \u2013 b\u0119dzie dok\u0142adnie na odwr\u00f3t, z t\u0105 r\u00f3\u017cnic\u0105, i\u017c <em>testujemy<\/em> zostanie ukazane po 5 sekundach. Wynika to w\u0142a\u015bnie z powodu <strong>asynchroniczno\u015bci<\/strong>. To tak, jakby\u015bmy programowali co\u015b w stylu wielow\u0105tkowych skrypt\u00f3w.<\/p>\n<h3>Co z AJAX?<\/h3>\n<p>Wrzu\u0107my teraz na warsztat jakie\u015b proste \u017c\u0105danie AJAX napisane w jQuery:<\/p>\n<p><code lang=\"javascript\">$.get('skrypt.php', function(data){ alert('data'); });<\/code><\/p>\n<p>Na pewno zauwa\u017cy\u0142e\u015b analogi\u0119 do powy\u017cszego przyk\u0142adu. Tu r\u00f3wnie\u017c mamy do czynienia z callbackiem. Nie zawsze jest to komfortowa sytuacja, zw\u0142aszcza w przypadku sprawdzania jakich\u015b danych przez osobn\u0105 funkcj\u0119, np:<\/p>\n<p><code lang=\"javascript\">function checkLogin(login){<br \/>\n\u00a0\u00a0\u00a0\u00a0 $.get('skrypt', { user: login }, function(data){ return data; });<br \/>\n}<br \/>\nalert(checkLogin('ja'));<\/code><\/p>\n<p>I co w\u00f3wczas? Funkcja nie zwr\u00f3ci niczego. Teraz wyja\u015bnijmy, dlaczego tak si\u0119 dzieje. Ot\u00f3\u017c \u2013 konstrukcja <em>return<\/em> u\u017cyta w callbacku zwraca dane \u2013 tak naprawd\u0119 \u2013 do frameworka, a nie do naszej funkcji. Jest to do\u015b\u0107 cz\u0119sty b\u0142\u0105d, kt\u00f3ry wymaga nieco potu. Zacznijmy od najprostszego rozwi\u0105zania&#8230;<\/p>\n<h3>\u017b\u0105danie synchroniczne<\/h3>\n<p>Obiekt <em>XmlHttpRequest<\/em>, z kt\u00f3rego korzysta ka\u017cda biblioteka AJAX posiada w\u0142asno\u015b\u0107 umo\u017cliwiaj\u0105c\u0105 wys\u0142anie \u017c\u0105dania synchronicznego. Pozwala ono na uzyskanie mniej-wi\u0119cej takiego efektu:<\/p>\n<p><code lang=\"javascript\">function checkLogin(login){<br \/>\n\u00a0\u00a0\u00a0\u00a0 var result = '';<br \/>\n\u00a0\u00a0\u00a0\u00a0 $.ajax({url: 'skrypt', data: { user: login }, success: function(data){ result = data; }, async: false});<br \/>\n\u00a0\u00a0\u00a0\u00a0 return result;<br \/>\n}<\/code><\/p>\n<p>Niestety, ma to do\u015b\u0107 powa\u017cn\u0105 wad\u0119 \u2013 dzia\u0142anie skrypt\u00f3w jest zamra\u017cane na czas \u017c\u0105dania, co uniemo\u017cliwia dzia\u0142anie innych w\u0105tk\u00f3w naszej aplikacji.<\/p>\n<h3>Wykorzystanie callback\u00f3w<\/h3>\n<p>Pozostaje \u2013 w takim razie \u2013 wykorzysta\u0107 w jaki\u015b spos\u00f3b wspomniane przeze mnie wy\u017cej callbacki.<\/p>\n<p><code lang=\"javascript\">function checkLogin(login, callback){<br \/>\n\u00a0\u00a0\u00a0\u00a0 $.get('skrypt', { user: login; }, function(data){ callback((data=='ok') });<br \/>\n});<br \/>\n}<\/code><\/p>\n<p>Co spowoduje wywo\u0142ywanie funkcji podanej jako callback z parametrem bool (prawda\/fa\u0142sz). W naszym skrypcie mo\u017cna zrealizowa\u0107 to mniej wi\u0119cej w ten spos\u00f3b:<\/p>\n<p><code lang=\"javascript\">var login = $('#login').val();<br \/>\ncheckLogin(login, function(isFree){<br \/>\n\u00a0\u00a0\u00a0\u00a0 if(isFree){<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 alert('login jest wolny');<br \/>\n\u00a0\u00a0\u00a0\u00a0 }else{<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 alert('login jest zaj\u0119ty');<br \/>\n\u00a0\u00a0\u00a0\u00a0 }<br \/>\n});<\/code><\/p>\n<p>Wad\u0105 tego rozwi\u0105zania jest konieczno\u015b\u0107 umieszczenia dalszej logiki funkcji w callbacku, co nie musi by\u0107 koniecznie czytelne. Zalet\u0105 \u2013 mo\u017cliwo\u015b\u0107 zachowania wielow\u0105tkowo\u015bci (np. Sprawdzanie wielu p\u00f3l naraz).<\/p>\n<h3>Jak to wygl\u0105da?<\/h3>\n<p>No sam(a) widzisz. \u00a0S\u0119k w tym, i\u017c nie ma \u2013 mi znanego \u2013 jakiego\u015b innego sposobu, kt\u00f3ry umo\u017cliwi\u0142by strukturalne przetworzenie takiego kodu. Wynika to g\u0142\u00f3wnie ze specyfiki oraz kontekstu wywo\u0142ywania funkcji obs\u0142ugi zdarze\u0144.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>O tym, \u017ce jQuery jest niez\u0142ym narz\u0119dziem, nie trzeba nikogo przekonywa\u0107. Filozofia \u0142a\u0144cuchowania \u2013 mam na my\u015bli konstrukcj\u0119 \u2013 nie jest jednak taka oczywista w u\u017cytku pod ka\u017cdym wzgl\u0119dem. Z jQuery da si\u0119 wygodnie pracowa\u0107; to, \u017ce co\u015b nie wychodzi wcale nie oznacza, i\u017c trzeba od razu zmienia\u0107 u\u017cywanego frameworka. Wystarczy zrozumie\u0107 kilka rzeczy. Notka [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,12],"tags":[100,79,93],"_links":{"self":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/posts\/218"}],"collection":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/comments?post=218"}],"version-history":[{"count":0,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/posts\/218\/revisions"}],"wp:attachment":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/media?parent=218"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/categories?post=218"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/tags?post=218"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}