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!
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('click', bindSecondButton); } function bindSecondButton() { b2.addEventListener('click', throwError); } function throwError() { throw new Error('aw shucks'); } main(); </script>
这是一个简单的 HTML 页面。页面加载时会给第一个按钮添加点击事件,其点击事件函数的功能是给第二个按钮添加点击事件,而第二个按钮的点击事件函数功能是抛出一个异常。我们依次点击第一个按钮和第二个按钮,控制台显示如下:
(索引):26 Uncaught Error: aw shucks at HTMLButtonElement.throwError ((索引):26:13)
但是如果我们通过zone.js
启动运行代码,控制台输出会有什么不同呢,我们先调整启动代码:
Zone.current.fork( { name: 'error', onHandleError: function (parentZoneDelegate, currentZone, targetZone, error) { console.log(error.stack); } } ).fork(Zone.longStackTraceZoneSpec).run(main);
此时控制台输出如下:
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)
通过对比我们知道:不引入zone.js
时,我们通过错误调用栈仅仅能够知道,异常是由按钮2的点击函数抛出。而引入了zone.js
后,我们不仅知道异常是由按钮2的点击函数抛出,还知道它的点击函数是由按钮1的点击函数绑定的,甚至能够知道最开始的应用启动是main
函数触发。这种能够持续追踪多个异步任务的能力在大型复杂项目中异常重要,现在我们来看zone.js
是如何做到的吧。
zone.js
接管了浏览器提供的异步 API,比如点击事件、计时器等等。也正是因为这样,它才能够对异步操作有更强的控制介入能力,提供更多的能力。现在我们拿点击事件举例,看看它是如何做到的吧。
proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener,..)
上述代码中,proto
便指的是EventTarget.prototype
,也就是说这行代码重新定义了addEventListener
函数。我们继续看看makeAddListener
函数做了什么。
function makeAddListener() { ...... // 关键代码1 nativeListener.apply(this, arguments); ...... // 关键代码2 const task = zone.scheduleEventTask(source, ...) ...... }
该函数主要做了两件事,一是在自定义函数中执行浏览器本身提供的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; }
文章开头控制台输出的完整的函数调用栈,存储在currentTask.data[creationTrace]
里面,它是一个由LongStackTrace
实例组成的数组。每次有异步任务发生时,onScheduleTask
函数便把当前函数调用栈存储记录下来,我们看看类LongStackTrace
的构造器就知道了:
class LongStackTrace { constructor() { this.error = getStacktrace(); this.timestamp = new Date(); } } function getStacktraceWithUncaughtError() { return new Error(ERROR_TAG); }
this.error
存储的便是函数调用栈,getStacktrace
函数通常调用的是getStacktraceWithUncaughtError
函数,我们看到new Error
大概就能够知道整个调用栈是如何得来的了。
本文分析的只是zone.js
能力的一个示例,如果你希望了解更多功能可以参阅官方文档。通过这个示例,希望读者能对zone.js
Angular-Tutorial
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!