SoFunction
Updated on 2025-04-11

Use of Angular asynchronous execution learning

What is Zone?

Maybe you've heard of Angular, but why should Angular be used, What functions can it provide? Today we will write a separate article to talk about it, about its role in the Angular framework will be discussed in the next article.

What is Zone? The official documentation explains this: Zone is an execution context that spans multiple asynchronous tasks. In a word, Zone has particularly powerful abilities in intercepting or tracking asynchronous tasks.

Analysis of working principle

Below we will demonstrate its capabilities through an example and briefly analyze the working principle behind it.

<button >Bind Error</button>
<button >Cause Error</button>
<script>
  function main() {
    ('click', bindSecondButton);
  }
  function bindSecondButton() {
    ('click', throwError);
  }
  function throwError() {
    throw new Error('aw shucks');
  }
  main();
</script>

This is a simple HTML page. When the page loads, a click event will be added to the first button. The function of the click event is to add a click event to the second button, while the function of the click event of the second button is to throw an exception. We click the first button and the second button in turn, and the console displays as follows:

(Index): 26 Uncaught Error: aw shucks
at (((index):26:13)

start up

But if we passStart the running code, what will be the difference in the console output? Let's adjust the startup code first:

(
      {
        name: 'error',
        onHandleError: function (parentZoneDelegate, currentZone, targetZone, error) {
          ();
        }
      }
    ).fork().run(main);

At this time, the console output is as follows:

Error: aw shucks
at (((index):26:13)
    at (:406:31)
    at (:178:47)
    at [as invoke] (:487:34)
    at invokeTask (:1600:14)
    at (:1626:17)
    at ____________________Elapsed_571_ms__At__Mon_Jan_31_2022_20_09_09_GMT_0800_________ (localhost)
    at (:105:22)
    at (:386:51)
    at (:221:43)
    at (:247:25)
    at (:1907:35)
at ((index):23:10)
    at (:406:31)
    at (:178:47)
    at ____________________Elapsed_2508_ms__At__Mon_Jan_31_2022_20_09_06_GMT_0800_________ (localhost)
    at (:105:22)
    at (:386:51)
    at (:221:43)
    at (:247:25)
    at (:1907:35)
at main ((index):20:10)
    at (:372:26)
    at (:134:43)

By comparison, we know: not to introduceWhen we use the error call stack, we can only know that the exception is thrown by the click function of button 2. And introducedAfter that, we not only know that the exception is thrown by the click function of button 2, but also know that its click function is bound by the click function of button 1, and we can even know that the initial application startup ismainFunction triggers. This ability to continuously track multiple asynchronous tasks is extremely important in large and complex projects. Now let's take a look at itHow to do it.

Take over the asynchronous API provided by the browser, such as click events, timers, etc. It is precisely because of this that it can have stronger control and intervention capabilities for asynchronous operations and provide more capabilities. Now let’s take the click event as an example and see how it is done.

proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener,..)

In the above code,protoThat means, that is, this line of code has been redefinedaddEventListenerfunction.

makeAddListener function

Let's continue to take a lookmakeAddListenerWhat does the function do.

function makeAddListener() {
  ......
  // Key Code 1  (this, arguments);
  ......
  // Key Code 2  const task = (source, ...)
  ......
}

This function mainly does two things. One is to execute the browser itself provided by the custom functionaddEventListenerThe other is to arrange an event task for each click function, which is alsoAn important factor in having strong intervention capabilities in asynchronous APIs.

Now let's go back to the example at the beginning of this article to see why the console can output a complete function call stack. We just analyzed itmakeAddListenerfunction, which mentions that it arranges an event task for each click function, that isExecution of functions. This event task function actually executesonScheduleTask:

onScheduleTask: function (..., task) {
  const currentTask = ;
  let trace = currentTask &&  && [creationTrace] || [];
  trace = [new LongStackTrace()].concat(trace);
  [creationTrace] = trace;
}

The complete function call stack output from the console at the beginning of the article, stored in[creationTrace]Inside, it is aLongStackTraceAn array of instances. Every time an asynchronous task occurs,onScheduleTaskThe function records the current function call stack storage, let's look at the classLongStackTraceThe constructor will know:

class LongStackTrace {
    constructor() {
         = getStacktrace();
         = new Date();
    }
}
function getStacktraceWithUncaughtError() {
    return new Error(ERROR_TAG);
}

What is stored is the function call stack.getStacktraceThe function usually callsgetStacktraceWithUncaughtErrorFunctions, we see new ErrorYou can probably know how the entire call stack is obtained.

This article only analyzesAn example of capabilities, if you wish to learn more about features, please refer to the official documentation. Through this example, I hope the reader can understandI have a general understanding, because it is also an indispensable cornerstone of Angular change detection. For more information about Angular asynchronous execution of zones, please pay attention to my other related articles!