ajax - Why isn't my future value available now? -


my ajax call not returning anything! here code:

var answer; $.getjson('/foo.json') . done(function(response) { answer = response.data; }); console.log(answer); 

even though network call succeeding, , can see response contains data, console logs "undefined"! happening?

we find ourselves in universe appears progress along dimension call "time". don't understand time is, have developed abstractions , vocabulary let reason , talk it: "past", "present", "future", "before", "after".

the computer systems build--more , more--have time important dimension. things set happen in future. other things need happen after first things occur. basic notion called "asynchronicity". in our increasingly networked world, common case of asynchonicity waiting remote system response request.

consider example. call milkman , order milk. when comes, want put in coffee. can't put milk in coffee right now, because not here yet. have wait come before putting in coffee. in other words, following won't work:

var milk = order_milk(); put_in_coffee(milk); 

because js has no way know needs wait order_milk finish before executes put_in_coffee. in other words, not know order_milk asynchronous--is not going result in milk until future time. js, , other declarative languages, execute 1 statement after without waiting.

the classic js approach problem, taking advantage of fact js supports functions first-class objects can passed around, pass function parameter asynchonous request, invoke when has complete task sometime in future. "callback" approach. looks this:

order_milk(put_in_coffee); 

order_milk kicks off, orders milk, then, when , when arrives, invokes put_in_coffee.

the problem callback approach pollutes normal semantics of function reporting result return; instead, functions must nost reports results calling callback given parameter. also, approach can rapidly become unwieldy when dealing longer sequences of events. example, let's want wait milk put in coffee, , , perform third step, namely drinking coffee. end needing write this:

order_milk(function(milk) { put_in_coffee(milk, drink_coffee); } 

where passing put_in_coffee both milk put in it, , action (drink_coffee) execute once milk has been put in. such code becomes hard write, , read, , debug.

in case, rewrite code in question as:

var answer; $.ajax('/foo.json') . done(function(response) {   callback(response.data); });  function callback(data) {   console.log(data); } 

enter promises

this motivation notion of "promise", particular type of value represents future or asynchronous outcome of sort. can represent happened, or going happen in future, or might never happen @ all. promises have single method, named then, pass action executed when outcome promise represents has been realized.

in case of our milk , coffee, design order_milk return promise milk arriving, specify put_in_coffee then action, follows:

order_milk() . then(put_in_coffee) 

one advantage of can string these create sequences of future occurrences ("chaining"):

order_milk() . then(put_in_coffee) . then(drink_coffee) 

let's apply promises particular problem. wrap our request logic inside function, returns promise:

function get_data() {   return $.ajax('/foo.json');  loadfile: function(file) {     //get json object     return $.getjson("/" + language.language + "/lang/" + file, function( data ) {         //go through each item in json object , add          $.each( data, function( key, val ) {             console.log(key+":"+val);             language.words[key]=val;                //add word         });     }); }, 

actually, we've done added return call $.ajax. works because jquery's $.ajax returns kind of promise-like thing. (in practice, without getting details, prefer wrap call return real promise, or use alternative $.ajax so.) now, if want load file , wait finish , something, can

get_data() . then(do_something) 

for instance,

get_data() .    then(function(data) { console.log(data); }); 

when using promises, end passing lots of functions then, it's helpful use more compact es6-style arrow functions:

get_data() .    then(data => console.log(data)); 

the async keyword

but there's still vaguely dissatisfying having write code 1 way if synchronous , quite different way if asynchronous. synchronous, write

a(); b(); 

but if a asynchronous, promises have write

a() . then(b); 

above, said "js has no way know needs wait first call finish before executes second". wouldn't nice if there was way tell js that? turns out there is--the await keyword, used inside special type of function called "async" function. feature part of upcoming version of es, available in transpilers such babel given right presets. allows write

async function morning_routine() {   var milk   = await order_milk();   var coffee = await put_in_coffee(milk);   await drink(coffee); } 

in case, able write

async function foo() {   data = await get_data();   console.log(data); } 

Comments