Thursday 15 August 2013

javascript - How do I return the response from an asynchronous call? -



javascript - How do I return the response from an asynchronous call? -

i have function foo makes ajax request. how can homecoming response foo?

i tried homecoming value success callback assigning response local variable within function , homecoming one, none of ways homecoming response.

function foo() { var result; $.ajax({ url: '...', success: function(response) { result = response; // homecoming response; // <- tried 1 } }); homecoming result; } var result = foo(); // ends beingness `undefined`.

-> more general explanation of async behavior different examples, please see why variable unaltered after modify within of function? - asynchronous code reference

-> if understand problem, skip possible solutions below.

explanation of problem

the a in ajax stands asynchronous. means sending request (or rather receiving response) taken out of normal execution flow. in example, $.ajax returns , next statement, return result;, executed before function passed success callback called.

here analogy makes difference between synchronous , asynchronous flow clearer:

synchronous

imagine create phone phone call friend , inquire him you. although might take while, wait on phone , stare space, until friend gives reply needed.

the same happening when create function phone call containing "normal" code:

function finditem() { var item; while(item_not_found) { // search } homecoming item; } var item = finditem(); // item dosomethingelse();

even though finditem might take long time execute, code coming after var item = finditem(); has wait until function returns result.

asynchronous

you phone call friend 1 time again same reason. time tell him in hurry , should call back on mobile phone. hang up, leave house , whatever planned do. 1 time friend calls back, dealing info gave you.

that's what's happening when ajax request.

finditem(function(item) { // item }); dosomethingelse();

instead of waiting response, execution continues , statement after ajax phone call executed. response eventually, provide function called 1 time response received, callback (notice something? call back ?). statement coming after phone call executed before callback called.

solution(s)

embrace asynchronous nature of javascript! while asynchronous operations provide synchronous counterparts (so "ajax"), it's discouraged utilize them, in browser context.

why bad ask?

javascript runs in ui thread of browser , long running process lock ui, making unresponsive. additionally, there upper limit on execution time javascript , browser inquire user whether go on execution or not.

all of bad user experience. user won't able tell whether working fine or not. furthermore effect worse users slow connection.

restructure code let functions take callbacks

the improve approach organize code around callbacks. in illustration in question, can create foo take callback , utilize success callback. this

var result = foo(); // code depends on 'result'

becomes

foo(function(result) { // code depends on 'result' });

here pass function argument foo. can pass function reference, example:

function mycallback(result) { // code depends on 'result' } foo(mycallback);

foo defined follows:

function foo(callback) { $.ajax({ // ... success: callback }); }

callback refer function pass foo when phone call , pass on success. i.e. 1 time ajax request successful, $.ajax phone call callback , pass response callback (which can referred result, since how defined callback).

you can process response before passing callback:

function foo(callback) { $.ajax({ // ... success: function(response) { // example, filter response callback(filtered_response); } }); }

it's easier write code using callbacks seems. after all, javascript in browser heavily event driven (dom events). receiving ajax response nil else event. difficulties arise when have work 3rd party code, problems can solved thinking through application flow.

use promises

the promise api new feature of ecmascript 6, has browser support already. there many libraries implement standard promises api , provide additional methods ease utilize , composition of asynchronous functions (e.g. bluebird).

promises containers future values. when promise receives value (it resolved) or when cancelled (rejected), notifies of "listeners" want access value.

the advantage on plain callbacks allow decouple code , easier compose.

here simple illustration of using promise:

function delay() { // `delay` returns promise homecoming new promise(function(resolve, reject) { // `delay` able resolve or reject promise settimeout(function() { resolve(42); // after 3 seconds, resolve promise value 42 }, 3000); }); } delay().then(function(v) { // `delay` returns promise console.log(v); // log value 1 time resolved }).catch(function(v) { // or else if rejected // (it not happen in example, since `reject` not called). });

applied our ajax phone call utilize promises this:

function ajax(url) { homecoming new promise(function(resolve, reject) { var xhr = new xmlhttprequest(); xhr.onload = function() { resolve(this.responsetext); }; xhr.onerror = reject; xhr.open('get', url); xhr.send(); }); } ajax("/echo/json").then(function(result) { // code depending on result }).catch(function() { // error occurred });

describing advantages promises offer beyond scope of answer, if write new code, should consider them. provide great abstraction , separation of code.

more info promises: html5 rocks - javascript promises

jquery: utilize deferred objects

deferred objects jquery's custom implementation of promises (before promise api standardized). behave promises, expose different api.

every ajax method of jquery returns "deferred object" (actually promise of deferred object) can homecoming function:

function ajax() { homecoming $.ajax(...); } ajax().done(function(result) { // code depending on result }).fail(function() { // error occurred });

promise gotchas

keep in mind promises , deferred objects containers future value, not value itself. example, suppose had following:

function checkpassword() { homecoming $.ajax({ url: '/password', data: { username: $('#username').val(), password: $('#password').val() }, type: 'post', datatype: 'json' }); } if (checkpassword()) { // tell user they're logged in }

this code misunderstands above asynchrony issues. specifically, $.ajax() doesn't freeze code while checks '/password' page on server - sends request server , while waits, returns jquery ajax deferred object, not response server. means if statement going deferred object, treat true, , proceed though user logged in. not good.

but prepare easy:

checkpassword() .done(function(r) { if (r) { // tell user they're logged in } else { // tell user password bad } }) .fail(function(x) { // tell user bad happened });

so we're still calling '/password' page on server, our code handles wait time server respond. $.ajax() phone call still returns jquery ajax deferred object, utilize attach event listeners .done() , .fail(). in .done() call, server responded normal response (http 200), check object returned server. in illustration server returning true if login successful, false if not, if (r) checking true/false.

in .fail() handler we're dealing going wrong - illustration if user lost net connection while typing in username , password, or if server went down.

not recommended: synchronous "ajax" calls

as mentioned, asynchronous operations have synchronous counterparts. while don't advocate there use, completeness, here how perform synchronous call:

without jquery

if straight utilize xmlhttprequest object, pass false 3rd argument .open.

jquery

if utilize jquery, can set async alternative false. note alternative deprecated since jquery 1.8. can either still utilize success callback or access responsetext property of jqxhr object:

function foo() { var jqxhr = $.ajax({ //... async: false }); homecoming jqxhr.responsetext; }

if utilize other jquery ajax method, such $.get, $.getjson, etc., have alter $.ajax (since can pass configuration parameters $.ajax).

heads up! not possible create synchronous jsonp request. jsonp nature asynchronous (one more reason not consider option).

javascript jquery ajax asynchronous

No comments:

Post a Comment