recursion - Understanding Event Queue and Call stack in javascript -


my curiosity understanding concept of "event queue" , "call stack" started when solving question:

var list = readhugelist();  var nextlistitem = function() {     var item = list.pop();      if (item) {         // process list item...         nextlistitem();     } }; 

the following recursive code cause stack overflow if array list large. how can fix , still retain recursive pattern?

the solution mentioned this:

var list = readhugelist();  var nextlistitem = function() {     var item = list.pop();      if (item) {         // process list item...         settimeout( nextlistitem, 0);     } }; 

solution:

the stack overflow eliminated because event loop handles recursion, not call stack. when nextlistitem runs, if item not null, timeout function (nextlistitem) pushed event queue , function exits, thereby leaving call stack clear. when event queue runs timed-out event, next item processed , timer set again invoke nextlistitem. accordingly, method processed start finish without direct recursive call, call stack remains clear, regardless of number of iterations.

now question:

q1) difference between "event queue" , "call stack"

q2) did not understand answer. can explain me in detail?

q3) when execute function or call variable or object in javascript. how flow go? what goes in call stack? (let's settimeout.. go callstack or event queue?)

these concepts unclear. googled of results aren't expecting understand.

please help!

answer 1 & 3

there big difference between event queue , call stack. in fact, have nothing in common.

call stack (simple overview):

when execute function uses said go on stack, same call stack you're referring there. simplified, it's temporary memory functional execution. or in other words

function foo() {    console.log("-> start [foo]");    console.log("<- end   [foo]");  }    foo();

when called given little sandbox play on stack. when function ends, temporary memory used wiped , made available other things. so, resources used (unless given somewhere system) last long function lasts.

now, if have nested functions

function foo() {    console.log("-> start [foo]");    console.log("<- end   [foo]");  }    function bar() {    console.log("-> start [bar]");    foo()    console.log("<- end   [bar]");  }    bar();

here happens when call function:

  1. bar gets executed - memory allocated on stack it.
  2. bar prints "start"
  3. foo gets executed - memory allocated on stack it. nb! bar still running , memory there.
  4. foo prints "start"
  5. foo prints "end"
  6. foo finishes execution , memory cleared stack.
  7. bar prints "end"
  8. bar finishes execution , memory cleared stack.

so, execution order bar -> foo resolution in last in, first out order (lifo) foo finishes -> bar finishes.

and makes "stack".

the important thing note here resources used function released when finishes executing. , finishes execution when functions inside , inside them finish executing. have deep call stack a -> b -> c -> d -> e , if large resources held in a need b e finish before released.

in recursion function calls still makes entries on stack. so, if a keeps calling end call stack of a -> a -> a -> a etc.

here brief illustration

// naive recursive count down function  function recursivecountdown(count) {    //show started    console.log("-> start recursivecountdown [" + count + "]");        if (count !== 0) {//exit condition      //take 1 off count , recursively call again      recursivecountdown(count -1);      console.log("<- end recursivecountdown [" + count + "]"); // show stopped. terminate stack after line above finished executing;    } else {      console.log("<<<- it's final recursivecountdown! [" + count + "]"); // show stopped    }  }    console.log("--shallow call stack--")  recursivecountdown(2);    console.log("--deep call stack--")  recursivecountdown(10);

this simplistic , flawed recursive function serves demonstrate happens in case.

event queue

javascript ran in event queue (or "event loop") which, in simple terms, waits "activity" (events), processes them , waits again.

if there multiple events, process them in order - first in, first out (fifo), hence queue. so, if re-write above functions:

function foo() {    console.log("-> start [foo]");    console.log("<- end   [foo]");  }    function bar() {    console.log("-> start [bar]");    console.log("<- end   [bar]");  }      function baz() {    console.log("-> start [baz]");        settimeout(foo, 0);    settimeout(bar, 0);        console.log("<- end   [baz]");  }    baz();

here how plays out.

  1. baz executed. memory allocated on stack.
  2. foo delayed scheduling run "next".
  3. bar delayed scheduling run "next".
  4. baz finishes. stack cleared.
  5. event loop picks next item on queue - foo.
  6. foo gets executed. memory allocated on stack.
  7. foo finishes. stack cleared.
  8. event loop picks next item on queue - bar.
  9. bar gets executed. memory allocated on stack.
  10. bar finishes. stack cleared.

as can see, stack still in play. function call generate stack entry. event queue separate mechanism.

with way of doing things, less memory overhead, since not have way on other function release allocated resources. on other hand, cannot rely on function being complete.

i hope section answers q3.

answer 2

how deferring queue help?

i hope above explanation make more clear bears making sure explanation makes sense:

there set limit of how deep stack be. if think it, should obvious - there memory spare presumably temporary storage. once maximum call depth reached, javascript throw rangeerror: maximum call stack size exceeded error.

if @ recursivecountdown example gave above can made cause error - if call recursivecountdown(100000) rangeerror.

by putting every other execution on queue, avoid filling stack , avoid rangeerror. let's re-write function

// still naive bit improved recursive count down function  function betterrecursivecountdown(count) {    console.log("-> start recursivecountdown [" + count + "]");        if (count !== 0) {      //settimeout takes more 2 parameters - after second 1 passed function when gets executed      settimeout(betterrecursivecountdown, 0, count - 1);      console.log("<- end recursivecountdown [" + count + "]");    } else {      console.log("<<<- it's final recursivecountdown! [" + count + "]"); // show stopped    }  }    betterrecursivecountdown(10);


Comments

Popular posts from this blog

javascript - Thinglink image not visible until browser resize -

firebird - Error "invalid transaction handle (expecting explicit transaction start)" executing script from Delphi -

mongodb - How to keep track of users making Stripe Payments -