이 기사에서는 Angular의 zone.js를 살펴보고, 예제를 통해 zone.js의 기능을 보여주고, 그 뒤에 있는 작동 원리를 간략하게 분석합니다. 모든 사람에게 도움이 되기를 바랍니다.
아마도 Angular가 zone.js
를 사용한다는 말을 들어보셨을 것입니다. 그런데 Angular는 왜 zone.js
를 사용하고 어떤 기능을 제공할 수 있나요? 오늘 우리는 zone.js
에 대해 이야기하기 위해 별도의 기사를 작성할 것입니다. Angular 프레임워크에서의 역할은 다음 기사에서 논의될 것입니다. [관련 튜토리얼 추천: "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
를 통해 코드를 실행하기 시작하면 콘솔 출력의 차이점은 무엇입니까? ? 먼저 시작 코드를 조정해 보겠습니다. 🎜rrreee🎜콘솔 출력은 다음과 같습니다. 🎜rrreee🎜비교를 통해 알 수 있습니다. zone.js
가 도입되지 않은 경우 오류 호출을 통해서만 알 수 있습니다. 버튼 2로 인해 예외가 발생한 스택 클릭 기능이 발생합니다. zone.js
를 소개한 후, 우리는 버튼 2의 클릭 기능에 의해 예외가 발생한다는 것을 알 뿐만 아니라 해당 클릭 기능이 버튼 1의 클릭 기능에 묶여 있다는 것도 알게 되었습니다. 최신 초기 애플리케이션 시작은 main
함수에 의해 트리거됩니다. 여러 비동기 작업을 지속적으로 추적하는 기능은 크고 복잡한 프로젝트에서 매우 중요합니다. 이제 zone.js
가 이를 어떻게 수행하는지 살펴보겠습니다. 🎜🎜zone.js
는 클릭 이벤트, 타이머 등과 같이 브라우저에서 제공하는 비동기 API를 대신합니다. 비동기 작업에 대한 더 강력한 제어 및 개입 기능을 보유하고 더 많은 기능을 제공할 수 있는 것은 바로 이 때문입니다. 이제 클릭 이벤트를 예로 들어 이것이 어떻게 수행되는지 살펴보겠습니다. 🎜rrreee🎜위 코드에서 proto
는 EventTarget.prototype
을 참조합니다. 이는 이 코드 줄이 addEventListener
함수를 재정의한다는 의미입니다. makeAddListener
함수가 수행하는 작업을 계속 살펴보겠습니다. 🎜rrreee🎜이 함수는 주로 두 가지 작업을 수행합니다. 하나는 브라우저 자체에서 제공하는 addEventListener
함수를 사용자 정의 함수에서 실행하는 것입니다. 또한 비동기 API에 개입하는 zone.js
의 강력한 기능에 있어서 중요한 요소이기도 합니다. 🎜🎜이제 이 글의 시작 부분에 있는 예로 돌아가 콘솔이 완전하고 완전한 함수 호출 스택을 출력할 수 있는 이유를 살펴보겠습니다. 우리는 방금 zone.scheduleEventTask
함수의 실행인 각 클릭 함수에 대해 이벤트 작업을 정렬한다고 언급한 makeAddListener
함수를 분석했습니다. 이 일정 이벤트 작업 함수는 실제로 onScheduleTask
를 실행합니다.🎜rrreee🎜기사 시작 부분에 있는 콘솔에서 출력된 전체 함수 호출 스택은 currentTask.data[creationTrace]에 저장되어 있습니다. code> - <code>LongStackTrace
인스턴스로 구성된 배열입니다. 비동기 작업이 발생할 때마다 onScheduleTask
함수는 현재 함수 호출 스택 저장소를 기록합니다. LongStackTrace
클래스의 생성자를 살펴보겠습니다. 🎜rrreee🎜 this.error는 함수 호출 스택을 저장합니다. getStacktrace
함수는 일반적으로 getStacktraceWithUncaughtError
함수를 호출합니다. 아마도 전체 호출 스택을 얻는 방법을 알 수 있을 것입니다. 🎜🎜이 글은 zone.js
기능의 예를 분석한 것입니다. 더 많은 기능을 알고 싶다면 공식 문서를 참조하세요. 이 예제를 통해 독자들이 zone.js
에 대한 전반적인 이해를 가질 수 있기를 바랍니다. 이는 Angular 변경 감지에 없어서는 안 될 초석이기도 하기 때문입니다. 이 부분에 대해서는 다음 글에서 설명하겠습니다. 🎜🎜더 많은 프로그래밍 관련 지식을 보려면 🎜프로그래밍 소개🎜를 방문하세요! ! 🎜위 내용은 Angular의 zone.js에 대한 심층 분석 및 작동 방식의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!