Let's say I have the following piece of code
function perpetuity() {
console.log("Being called");
setTimeout(perpetuity, 1500);
}
perpetuity();
I would like to know if the global execution context is present in the call stack so that this code can be executed.
OR
If the global execution context is created and deleted along with the callback function's execution context every 1500ms.
Chat gpt says GEC never stops but I cannot find the GEC in my browser's call stack when executing this.
There is no "global execution context". (I assume you're not confusing this with the global environment record?)
There is however a realm execution context for all js code running in a browser. It is not actually useful for anything and more of a technicality (to allow tracking the realm that caused the execution), but it is pushed to the execution context stack before running any JS code and popped afterwards. It is created in InitializeHostDefinedRealm together with the intrinsics, the global object and the global environment of the realm, to create the realm.
Related
I wanted to understand the internal mechanisms of a JavaScript engine for asynchronous functions, so I checked the Spec. For the rest of this question, I will refer to the linked version of the specification.
Section 6.2.3.1 describes this. Basically, a promise is created which is resolved to the expression that is awaited. The promise is then added resolving handlers via .then; The fulfillment handler is a function object created from an abstract closure which captures asyncContext which is the execution context associated to the asynchronous function. This abstract closure suspends the running execution context and restores asyncContext as the running execution context.
The thing I don't understand is:
when this abstract closure gets called, isn't the execution context associated with itself the running execution context? Wouldn't this abstract closure suspend itself then?
I believe so because .then [27.2.5.4.1 PerformPromiseThen] creates jobs via 27.2.2.1 NewPromiseReactionJob which creates an abstract closure that uses 9.5.3 HostCallJobCallback to call the handler which in turn must perform 7.3.14 Call on it, leading to an invocation of the [[Call]] internal method of the function object (10.2.1). This pushes a new execution context on the stack.
What am I misunderstanding? What does prevContext actually refer to in 6.2.3.1?
Your problem might be the idea that there's an execution context "associated with" the abstract closure. The spec is a bit cagey on this point, but I think it's easier to understand examples like yours if you imagine spec algorithms (including abstract closures) as running "outside" any execution context. This then allows spec algorithms to suspend/resume/push/pop execution contexts without any effect on the running of those algorithms.
I am studying hard what the closure is in Javascript.
According to MDN, closures are created every time a function is created, at function creation time.
However, many articles and answers in Stack Overflow says that the concept of closure needs the relationship between inner function and outer function and their variables.
So, I wonder whether 'global' is the kind of a function which executes at runtime of global scope(or global execution context) or not.
If 'global' is a function, all of the functions in script are maybe inner functions, I guess.
Please answer me if you are fully understanding closures, and execution contexts. Thank you!
your question is a very genuine one :). What I get from your question is that your confusion is in 'global' in JavaScript. It is not clear from your question if you need help in closures and execution context, so to keep the answer short I'll focus on "global" only.
So global in JavaScript is the global execution context. It is more like complier running the code.
If you have experience in any programming language say Java. You may relate to this. The place where you write functions is not a function itself. So we can safely say global is not a function rather an execution context.
Same way, the functions defined inside a global execution context are not inner functions. They are simply functions.
Maybe you are confused in this, because you feel the variables declared globally can be accessed inside the function declared in global concept, this is simply because of scope of a variable and has nothing to do with closures.
When we execute our code, one of the very first things that the JavaScript engine does is to create a global execution context. This has the same purpose as function execution context, but at the global level with some more particularities. Now, once GEC got created - JS engine moves line by line and starts to execute other functions with their own function execution context!
So as per your question, global is just an execution context that gets created only once at the beginning with some extra features.
Hope this could clear your doubt.
When JS code starts to run, the Global Execution Context is created and sits at the bottom of the execution stack as to "accomodate" Global Variable Object and'this'.
If it is the case for the execution stack to get empty after the whole JS code is run and there is no Global Execution Context, how are we still able to access the global variables (for example, I am running an html file with its JS code and after its completion, I am still able to see the values of global variables through Chrome console...) or how this still points to global object (there shouldn't be any 'this' if there wasn't any Execution Context!)?
The only explanation I may give to myself is that Global Execution Context never leaves the execution stack; it is always there till I decide to close the browser window. Am I right or not?
Moreover, in case of asynchronous callbacks, when an event gets out of the event queue and gets into JS engine as to be run, what exactly happens in the execution stack? Is the callback's execution context sitting at the bottom of this stack or the global execution context is still there?
There is a similar subject Is the initial global execution context ever popped off the call stack in JavaScript?; however, it does not answer my questions.
Thank you
The execution stack gets empty when the whole code is run.
how are we still able to access the global variables?
Even when no code is executed the global lexical environment with the global object still exists. When you feed some code into chrome console, the code is being evaluated, a new global execution context is being created and initialized with its lexical and variable environments set to the global environment and this bound to the global object. Then your code is executed within this context and the execution stack gets empty again.
how this still points to global object?
Every time a new global execution context is initialized with the global code, this gets bound to the global object.
in case of asynchronous callbacks, when an event gets out of the event queue and gets into JS engine as to be run, what exactly happens in the execution stack?
Again, a new global execution context is created and pushed onto the empty execution stack. In MDN this is described in slightly different terms than in ECMAScript spec:
When the stack is empty, a message is taken out of the queue and processed. The processing consists of calling the associated function (and thus creating an initial stack frame). The message processing ends when the stack becomes empty again. (MDN. Concurrency model and event loop)
Here "stack frame" means "execution context" and "initial stack frame" corresponds to "global execution context".
Is the callback's execution context sitting at the bottom of this stack or the global execution context is still there?
None of them. The stack is empty. And only if it is empty, the oldest callback is taken from the callback/event queue:
When there is no running execution context and the execution context stack is empty, the ECMAScript implementation removes the first PendingJob from a Job Queue and uses the information contained in it to create an execution context and starts execution of the associated Job abstract operation. ECMAScript 6.0 spec
Is the "initial global execution context" ever popped off the call stack in JavaScript? I am talking about the execution context that is at the bottom of the stack at all times.
If so, I presume this means it is pushed onto the stack first before a callback is picked up off the Job Queue?
Alternatively, is it the [[Scope]].outer chain that provides access to the global environment whenever a callback is pushed onto the stack?
Is the "initial global execution context" ever popped off the call stack in JavaScript? I am talking about the execution context that is at the bottom of the stack at all times.
Yes, it is. An empty execution context stack is the requirement for any jobs to run.
However, there is no such thing like an "initial global execution context", and since the stack can be empty there is no single context that is at the bottom of the stack all the time.
"Global execution contexts" are created in ScriptEvaluations. Every script does have its own scriptCxt, yet all of them in a shared realm carry the same global environment records. These scriptCtxs are not at the bottom at the stack, though.
An "initial execution context" that sits at the bottom of the stack is created in the ECMAScript Initialisation process. It is pretty meaningless, for it does not hold anything but the new realm and only serves as the context for the initialisation of the realm and global object, but it is also used to start off the job queues.
If so, I presume this means it is pushed onto the stack first before a callback is picked up off the Job Queue?
Yes indeed. We can see this from the instructions for the NextJob algorithm steps. These are performed at the end of the ECMAScript initialisation and end of every job, and basically read as follows:
Suspend the current execution context and pop it from the stack so that the stack is empty.
Get the next job from any queue. If there are no more, proceed as you want (i.e. typically shuts down the process).
Create a new, empty (except for the realm of the job) context newContext and put it at the bottom of the stack
Execute the selected job in this context (which starts over NextJob in the end)
These contexts serve as the base for every job, containing all execution that ever happens. In PromiseJobs, they are used rather directly, while in module- and script evaluation jobs other contexts will be pushed on the stack that serve to hold the respective environment records with whom the code should be executed.
Alternatively, is it the [[Scope]].outer chain that provides access to the global environment whenever a callback is pushed onto the stack?
Yes indeed. The scope chain (that is not to be confused with the execution context stack) does provide access from everywhere to the global environment, which sits at the end of every scope chain.
Lets say we have a sequence of functions being executed in the global scope, like so:
function second() {}
function first() {
second();
}
first();
When does first get added to the call stack?
Does it get added upon invocation, or does it get added after it calls second (and the execution context is now inside of second) ?
A function is "added to the stack" when it is called. While a "call stack" implementation is not specified in ECMAScript 5th edition it does define the virtual behavior in 10.3 Execution Contexts:
When control is transferred to ECMAScript executable code, control is entering an execution context. Active execution contexts logically form a stack. The top execution context on this logical stack is the running execution context [ie. currently running function]. A new execution context is created whenever control is transferred from the executable code associated with the currently running execution context to executable code that is not associated with that execution context. The newly created execution context is pushed onto the stack and becomes the running execution context.
It is not technically the function that is part of the stack, but rather the execution context created from invoking the function.
This also agrees with more general Call Stack concept where the active/current function context is also part of the stack.
In computer science, a call stack is a stack data structure that stores information about the active subroutines [including the subroutine currently running] of a computer program .. the details are normally hidden and automatic in high-level programming languages..
Using this definition also ensures a function is never running "off the stack" - which agrees with such a concept from other languages/environments and JavaScript developer tools.
function second() {/* 3rd code here will be executed once second is called */}
function first() {
// 2nd code here will be executed before second(); is called
second();
// 4th code here will be executed after second(); is called and all its code has been executed
}
// 1st code here will be executed before anything is called
first();
// 5th code here will be executed when everything has been called.