Heim > Web-Frontend > js-Tutorial > Hauptteil

Eine ausführliche Analyse von zone.js in Angular und seiner Funktionsweise

青灯夜游
Freigeben: 2022-02-15 10:11:36
nach vorne
2397 Leute haben es durchsucht

Dieser Artikel führt Sie durch Zone.js in Angular, demonstriert die Fähigkeiten von Zone.js anhand eines Beispiels und analysiert kurz das Funktionsprinzip dahinter. Ich hoffe, dass es für alle hilfreich ist!

Eine ausführliche Analyse von zone.js in Angular und seiner Funktionsweise

Vielleicht haben Sie gehört, dass Angular zone.js verwendet, aber warum verwendet Angular zone.js und welche Funktionen kann es bieten? Heute werden wir einen separaten Artikel schreiben, um über zone.js zu sprechen. Seine Rolle im Angular-Framework wird im nächsten Artikel besprochen. [Verwandte Tutorial-Empfehlung: „zone.js, 但 Angular 为什么要使用zone.js, 它能够提供哪些功能呢?今天我们单独写一篇文章聊聊zone.js,关于它在 Angular 框架中发挥的作用将在下一篇文章讲述。【相关教程推荐:《angular教程》】

什么是 Zone ? 官方文档是这么解释的:Zone 是一个跨多个异步任务的执行上下文。一句话总结来说,Zone 在拦截或追踪异步任务方面有着特别强大的能力。下面我们将通过一个示例来展示它的能力,并简单剖析一下背后的工作原理。

<button id="b1">Bind Error</button>
<button id="b2">Cause Error</button>
<script>
  function main() {
    b1.addEventListener(&#39;click&#39;, bindSecondButton);
  }
  function bindSecondButton() {
    b2.addEventListener(&#39;click&#39;, throwError);
  }
  function throwError() {
    throw new Error(&#39;aw shucks&#39;);
  }
  main();
</script>
Nach dem Login kopieren

这是一个简单的 HTML 页面。页面加载时会给第一个按钮添加点击事件,其点击事件函数的功能是给第二个按钮添加点击事件,而第二个按钮的点击事件函数功能是抛出一个异常。我们依次点击第一个按钮和第二个按钮,控制台显示如下:

(索引):26 Uncaught Error: aw shucks
    at HTMLButtonElement.throwError ((索引):26:13)
Nach dem Login kopieren

但是如果我们通过zone.js启动运行代码,控制台输出会有什么不同呢,我们先调整启动代码:

  Zone.current.fork(
      {
        name: &#39;error&#39;,
        onHandleError: function (parentZoneDelegate, currentZone, targetZone, error) {
          console.log(error.stack);
        }
      }
    ).fork(Zone.longStackTraceZoneSpec).run(main);
Nach dem Login kopieren

此时控制台输出如下:

Error: aw shucks
    at HTMLButtonElement.throwError ((索引):26:13)
    at ZoneDelegate.invokeTask (zone.js:406:31)
    at Zone.runTask (zone.js:178:47)
    at ZoneTask.invokeTask [as invoke] (zone.js:487:34)
    at invokeTask (zone.js:1600:14)
    at HTMLButtonElement.globalZoneAwareCallback (zone.js:1626:17)
    at ____________________Elapsed_571_ms__At__Mon_Jan_31_2022_20_09_09_GMT_0800_________ (localhost)
    at Object.onScheduleTask (long-stack-trace-zone.js:105:22)
    at ZoneDelegate.scheduleTask (zone.js:386:51)
    at Zone.scheduleTask (zone.js:221:43)
    at Zone.scheduleEventTask (zone.js:247:25)
    at HTMLButtonElement.addEventListener (zone.js:1907:35)
    at HTMLButtonElement.bindSecondButton ((索引):23:10)
    at ZoneDelegate.invokeTask (zone.js:406:31)
    at Zone.runTask (zone.js:178:47)
    at ____________________Elapsed_2508_ms__At__Mon_Jan_31_2022_20_09_06_GMT_0800_________ (localhost)
    at Object.onScheduleTask (long-stack-trace-zone.js:105:22)
    at ZoneDelegate.scheduleTask (zone.js:386:51)
    at Zone.scheduleTask (zone.js:221:43)
    at Zone.scheduleEventTask (zone.js:247:25)
    at HTMLButtonElement.addEventListener (zone.js:1907:35)
    at main ((索引):20:10)
    at ZoneDelegate.invoke (zone.js:372:26)
    at Zone.run (zone.js:134:43)
Nach dem Login kopieren

通过对比我们知道:不引入zone.js时,我们通过错误调用栈仅仅能够知道,异常是由按钮2的点击函数抛出。而引入了zone.js后,我们不仅知道异常是由按钮2的点击函数抛出,还知道它的点击函数是由按钮1的点击函数绑定的,甚至能够知道最开始的应用启动是main函数触发。这种能够持续追踪多个异步任务的能力在大型复杂项目中异常重要,现在我们来看zone.js是如何做到的吧。

zone.js接管了浏览器提供的异步 API,比如点击事件、计时器等等。也正是因为这样,它才能够对异步操作有更强的控制介入能力,提供更多的能力。现在我们拿点击事件举例,看看它是如何做到的吧。

proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener,..)
Nach dem Login kopieren

上述代码中,proto便指的是EventTarget.prototype,也就是说这行代码重新定义了addEventListener函数。我们继续看看makeAddListener函数做了什么。

function makeAddListener() {
  ......
  // 关键代码1
  nativeListener.apply(this, arguments);
  ......
  // 关键代码2
  const task = zone.scheduleEventTask(source, ...)
  ......
}
Nach dem Login kopieren

该函数主要做了两件事,一是在自定义函数中执行浏览器本身提供的addEventListener函数,另外一个就是为每个点击函数安排了一个事件任务,这也是zone.js对异步 API 有强大介入能力的重要因素。

现在我们再回到本文开头的示例中,看看控制台为什么能够输出完整的完整的函数调用栈。刚刚我们分析过了makeAddListener函数,其中提到它为每个点击函数安排了一个事件任务,也就是zone.scheduleEventTask函数的执行。这个安排事件任务函数最终其实执行的是onScheduleTask:

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

文章开头控制台输出的完整的函数调用栈,存储在currentTask.data[creationTrace]里面,它是一个由LongStackTrace实例组成的数组。每次有异步任务发生时,onScheduleTask函数便把当前函数调用栈存储记录下来,我们看看类LongStackTrace的构造器就知道了:

class LongStackTrace {
    constructor() {
        this.error = getStacktrace();
        this.timestamp = new Date();
    }
}
function getStacktraceWithUncaughtError() {
    return new Error(ERROR_TAG);
}
Nach dem Login kopieren

this.error存储的便是函数调用栈,getStacktrace函数通常调用的是getStacktraceWithUncaughtError函数,我们看到new Error大概就能够知道整个调用栈是如何得来的了。

本文分析的只是zone.js能力的一个示例,如果你希望了解更多功能可以参阅官方文档。通过这个示例,希望读者能对zone.jsAngular-Tutorial

“]

Was ist Zone? Das offizielle Dokument erklärt es so: Zone ist ein Ausführungskontext, der mehrere asynchrone Aufgaben umfasst. Kurz gesagt: Zone verfügt über eine besonders leistungsstarke Fähigkeit, asynchrone Aufgaben abzufangen oder zu verfolgen. Im Folgenden werden wir anhand eines Beispiels seine Fähigkeiten demonstrieren und kurz das Funktionsprinzip dahinter analysieren. rrreee

Dies ist eine einfache HTML-Seite. Wenn die Seite geladen wird, wird der ersten Schaltfläche ein Klickereignis hinzugefügt. Die Funktion der Klickereignisfunktion besteht darin, der zweiten Schaltfläche ein Klickereignis hinzuzufügen, und die Funktion der Klickereignisfunktion der zweiten Schaltfläche besteht darin, eine Ausnahme auszulösen. Wir klicken nacheinander auf die erste und die zweite Schaltfläche und die Konsole zeigt Folgendes an: 🎜rrreee🎜Aber wenn wir beginnen, den Code über zone.js auszuführen, was wird der Unterschied in der Konsolenausgabe sein? ? Passen wir zuerst den Startcode an: 🎜rrreee🎜Die Konsolenausgabe lautet wie folgt: 🎜rrreee🎜Im Vergleich dazu wissen wir: Wenn zone.js nicht eingeführt wird, können wir es nur durch den Fehleraufruf wissen Stapel, dass die Ausnahme durch Schaltfläche 2 verursacht wird. Die Klickfunktion löst aus. Nach der Einführung von zone.js wissen wir nicht nur, dass die Ausnahme durch die Klickfunktion von Schaltfläche 2 ausgelöst wird, sondern wissen auch, dass ihre Klickfunktion an die Klickfunktion von Schaltfläche 1 gebunden ist, und wissen es sogar die neueste Der erste Anwendungsstart wird durch die Funktion main ausgelöst. Diese Fähigkeit, mehrere asynchrone Aufgaben kontinuierlich zu verfolgen, ist in großen und komplexen Projekten äußerst wichtig. Sehen wir uns nun an, wie zone.js das macht. 🎜🎜zone.js übernimmt die vom Browser bereitgestellte asynchrone API, wie Klickereignisse, Timer usw. Gerade deshalb kann es über stärkere Kontroll- und Eingriffsmöglichkeiten für asynchrone Vorgänge verfügen und mehr Möglichkeiten bieten. Nehmen wir nun das Click-Ereignis als Beispiel und sehen wir uns an, wie es funktioniert. 🎜rrreee🎜Im obigen Code bezieht sich proto auf EventTarget.prototype, was bedeutet, dass diese Codezeile die Funktion addEventListener neu definiert. Sehen wir uns weiterhin an, was die Funktion makeAddListener bewirkt. 🎜rrreee🎜Diese Funktion führt hauptsächlich die vom Browser selbst bereitgestellte Funktion addEventListener aus. Die andere besteht darin, für jede Klickfunktion eine Ereignisaufgabe zu arrangieren Auch ein wichtiger Faktor für die starke Fähigkeit von zone.js, in asynchrone APIs einzugreifen. 🎜🎜Kehren wir nun zum Beispiel am Anfang dieses Artikels zurück und sehen wir uns an, warum die Konsole einen vollständigen Funktionsaufrufstapel ausgeben kann. Wir haben gerade die Funktion makeAddListener analysiert und erwähnt, dass sie für jede Klickfunktion eine Ereignisaufgabe anordnet, nämlich die Ausführung der Funktion zone.scheduleEventTask. Diese Funktion zur Planung von Ereignisaufgaben führt tatsächlich onScheduleTask aus:🎜rrreee🎜Der vollständige Funktionsaufrufstapel, der von der Konsole am Anfang des Artikels ausgegeben wird und in currentTask.data[creationTrace] gespeichert ist. code> , ein Array bestehend aus <code>LongStackTrace-Instanzen. Jedes Mal, wenn eine asynchrone Aufgabe auftritt, zeichnet die Funktion onScheduleTask den aktuellen Funktionsaufruf-Stack-Speicher auf. Schauen wir uns den Konstruktor der Klasse LongStackTrace an: 🎜rrreee🎜this. error speichert den Funktionsaufrufstapel. Die Funktion getStacktrace ruft normalerweise die Funktion getStacktrace auf wissen, wie der gesamte Aufrufstapel erhalten wird. 🎜🎜Dieser Artikel analysiert nur ein Beispiel der Funktionen von zone.js. Wenn Sie mehr über die Funktionen erfahren möchten, können Sie sich auf die offizielle Dokumentation beziehen. Ich hoffe, dass die Leser durch dieses Beispiel ein allgemeines Verständnis von zone.js erlangen können, da es auch ein unverzichtbarer Eckpfeiler der Winkeländerungserkennung ist. Ich werde diesen Aspekt im nächsten Artikel erläutern. 🎜🎜Weitere Kenntnisse zum Thema Programmierung finden Sie unter: 🎜Einführung in die Programmierung🎜! ! 🎜

Das obige ist der detaillierte Inhalt vonEine ausführliche Analyse von zone.js in Angular und seiner Funktionsweise. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:juejin.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage