深入Angular:(转&翻)Do you still think that NgZone (zone.js) is required for change detection in Angular?

这篇具有很好参考价值的文章主要介绍了深入Angular:(转&翻)Do you still think that NgZone (zone.js) is required for change detection in Angular?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原文链接:IndepthApp

前言概览:注意区分NgZone和zone.js, 更多细节在Angular跟新策略篇,尚未翻译完成。

Do you still think that NgZone (zone.js) is required for change detection in Angular?

abstract:This article explains why and how Angular implements NgZone over zone.js library. Read to learn how the framework can be used completely without zone.js and when automatic change detection can fail.

本文主要解释了Angular是如何基于zone.js实现NgZone。 同时阐述如何在不使用zone.js的情况下,实现手动更新。文章最后部分将描述自动跟新策略何时会失效。

我看过的大多数文章都将Zone(zone.js)和NgZone与Angular中的变更检测紧密关联在一起。尽管它们确实有关系,但从技术上讲,它们并不是一个整体的部分。是的,Zone和NgZone用于自动触发由异步操作引起的变更检测。但由于变更检测是一个单独的机制,它可以在没有Zone和NgZone的情况下成功工作。在第一章中,我将展示如何在没有zone.js的情况下使用Angular。文章的第二部分解释了Angular和zone.js如何通过NgZone进行互动。最后,我还会展示为什么自动变更检测有时无法与诸如Google API客户端库(gapi)等第三方库一起使用。

我已经撰写了许多关于Angular中变更检测的详细文章。如果您想全面了解变更检测的工作原理,我建议从阅读所有这些文章开始,其中包括本文。这5篇文章将使您成为Angular变更检测的专家。请注意,本文不涉及zone.js,而是关于Angular如何在实现NgZone时使用区域以及它与变更检测机制的关系。要了解更多关于区域的信息,请阅读我的Reverse-engineered Zones (zone.js)文章,其中包含了我所发现的内容。(IndepthApp)

Using Angular without Zone (zone.js) 在没有Zone.js的情况下使用NG

为了证明Angular可以在没有Zone的情况下成功工作,我最初计划提供一个模拟的区域对象,它什么也不做。但是,即将发布的Angular 5版本为我简化了这些事情。现在,通过配置方式,它提供了一种使用不执行任何操作的noop Zone的方法。

feat(core): support for bootstrap with custom zone (#17672) · angular/angular@344a5ca · GitHub

为了做到这一点,首先让我们删除对zone.js的依赖。我将使用StackBlitz来演示应用程序,并且由于它使用Angular-CLI,所以我将从polyfills.ts文件中删除以下导入语句:

* Zone JS is required by Angular itself. */
import 'zone.js/dist/zone';  // Included with Angular CLI.

之后,我将像这样配置Angular来使用noop Zone的实现:

platformBrowserDynamic()
    .bootstrapModule(AppModule, {
        ngZone: 'noop'
    });

如果您现在运行该应用程序(Angular (forked) - StackBlitz),您将看到更改检测是完全可操作的,并在DOM中呈现name组件属性。

现在尝试使用 setTimeout() 来更新属性:

export class AppComponent  {
    name = 'Angular 4';
 
    constructor() {
        setTimeout(() => {
            this.name = 'updated';
        }, 1000);
    }

很明显没有触发更新,由于在前置配置中把ngZone设为 'noop'。但是我可以获取组件的引用(ApplicationRef )的 tick( ) 方法来手动触发更新。

export class AppComponent  {
    name = 'Angular 4';
 
    constructor(app: ApplicationRef) {
        setTimeout(()=>{
            this.name = 'updated';
            app.tick();
        }, 1000);
    }

好的更新成功。代码案例:Angular (forked) - StackBlitz

总结下来, 上面演示的重点是向你展示zone.js和NgZone并不是变更检测实现的一部分。这是一种非常方便的机制,可以通过调用app.tick()来自动触发变更检测,而不是在某些时机手动执行。我们一会儿会看到这些时机是什么。

How NgZone uses Zones 了解NgZone是如何包装Zone.js的

此部分将演示了Zone提供的两个功能——上下文传播出色的异步任务跟踪。Angular实现的NgZone类在很大程度上依赖于任务跟踪机制。

NgZone只是包装了zone.js

function forkInnerZoneWithAngularBehavior(zone: NgZonePrivate) {
    zone._inner = zone._inner.fork({
        name: 'angular',
        ...

zone.js的部分功能被保在 _inner 属性里面,通常被称为Angular zone。 这是你执行NgZone.run()时用来运行的回调部分:

run(fn, applyThis, applyArgs) {
    return this._inner.run(fn, applyThis, applyArgs);
}

那么Angular拓展的zone.js的部分被保存在 _outer 属性中,并用于在执行NgZone.runOutsideAngular()时运行回调:

runOutsideAngular(fn) {
    return this._outer.run(fn);
}

这种方法通常用于在Angular区域之外运行性能要求很高的操作,以避免不断触发变更检测。

NgZone有一个isStable属性,用来表示是否没有未完成的宏或微任务。它还定义了四个事件:

+------------------+-----------------------------------------------+
|      Event       |                     Description               |
+------------------+-----------------------------------------------+
| onUnstable       | Notifies when code enters Angular Zone.       |
|                  | This gets fired first on VM Turn.             |
|                  |                                               |
| onMicrotaskEmpty | Notifies when there is no more microtasks     |
|                  | enqueued in the current VM Turn.              |
|                  | This is a hint for Angular to do change       |
|                  | detection which may enqueue more microtasks.  |
|                  | For this reason this event can fire multiple  |
|                  | times per VM Turn.                            |
|                  |                                               |
| onStable         | Notifies when the last `onMicrotaskEmpty` has |
|                  | run and there are no more microtasks, which   |
|                  | implies we are about to relinquish VM turn.   |
|                  | This event gets called just once.             |
|                  |                                               |
| onError          | Notifies that an error has been delivered.    |
+------------------+-----------------------------------------------+

Angular在ApplicationRef中使用onMicrotaskEmpty事件来自动触发变更检测:

this._zone.onMicrotaskEmpty.subscribe(
    {next: () => { this._zone.run(() => { this.tick(); }); }});

没错就是之前手动触发的方法 : app.tick( )

How NgZone implements onMicrotaskEmpty event 那么NgZone是如何实现onMicrotaskEmpty()方法的?

现在让我们看看NgZone是如何实现onMicrotaskEmpty事件的。事件由checkStable函数触发:

function checkStable(zone: NgZonePrivate) {
  if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
    try {
      zone._nesting++;
      zone.onMicrotaskEmpty.emit(null); look this line m???er fuck<-------------------

这个函数经常由三个钩子函数触发:

  • onHasTask
  • onInvokeTask
  • onInvoke

 正如在关于Zone的文章中所解释的,当最后两个钩子被触发时,微任务队列可能会发生变化,所以Angular必须在每次触发钩子时运行稳定检查。onhasask钩子也用于执行检查,因为它跟踪整个队列的变化。

Common pitfalls 常见的问题 

注:此章节的问题我个人暂时尚未遇见

stackoveflow中与变更检测相关的一个最常见的问题是,为什么有时在使用第三方库时,组件中的变更没有应用。这里有一个涉及Google API客户端库(gapi)的例子。解决这些问题的常见方法是在Angular zone中运行一个回调,如下所示:

gapi.load('auth2', () => {
    zone.run(() => {
        ...

然而,一个有趣的问题是为什么Zone不注册请求,这导致在一个钩子中没有通知?如果没有通知,NgZone不会自动触发变更检测。

为了了解这一点,我只是深入研究了gapi的源代码,发现它使用JSONP来发出网络请求。这种方法不使用常见的AJAX API,如XMLHttpRequest或Fetch API,这些API由zone修补和跟踪。相反,它创建一个带有源URL的脚本标记,并定义一个全局回调,当从服务器获取带有数据的请求脚本时将触发该回调。zone无法修补或检测到这一点,因此框架对使用这种技术执行的请求保持不知情。

以下是gapi最小化版本的相关片段,供好奇的人参考:

Ja = function(a) {
    var b = L.createElement(Z);
    b.setAttribute(“src”, a);
    a = Ia();
    null !== a && b.setAttribute(“nonce”, a);
    b.async = “true”;
    (a = L.getElementsByTagName(Z)[0]) ? 
        a.parentNode.insertBefore(b, a) : 
        (L.head || L.body || L.documentElement).appendChild(b)
}

变量Z等于"script",参数a保存请求URL:

https://apis.google.com/_.../cb=gapi.loaded_0

 URL的最后一段是gapi.loadd_0全局回调:文章来源地址https://www.toymoban.com/news/detail-792989.html

typeof gapi.loaded_0 
“function”

到了这里,关于深入Angular:(转&翻)Do you still think that NgZone (zone.js) is required for change detection in Angular?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 全网多种方法解决Updates were rejected because the remote contains work that you do not have locally的错误

    今天使用 git status 查看文件状态,发现有一个文件未提交,如下代码所示: 既然未提交,则首先使用 git add 将当前目录下修改的代码,从工作区添加到暂存区,如下代码所示: 接着使用 git commit 将缓存区内容添加到本地仓库,如下代码所示: 但使用 git push origin master 将本地

    2024年02月03日
    浏览(37)
  • 解决gitpush时报错:hint: Updates were rejected because the remote contains work that you do hint: not have

    当我新建了一个git仓库,依次执行 却报错 报这个错是因为远程仓库和本地仓库文件不同步,解决方法是先执行git pull将远程仓库文件拉下来使得远程与本地同步。 解决步骤 1.执行 这里的webbrowser换成你的远程仓库名 执行后会有如下输出 2.再试试重新推送行不行 发现还是报错

    2024年02月16日
    浏览(42)
  • Angular中的NgZone.run()有什么用?

    在Angular中,NgZone是一个服务,用于管理异步任务的执行,并提供一种在Angular区域内或外部显式运行代码的方式。区域(Zone)的概念用于跟踪和拦截异步操作,例如Promises、事件和定时器,以便在需要时触发变更检测。 NgZone.run方法是一种显式在Angular区域内运行函数的方式。

    2024年02月03日
    浏览(24)
  • [Angular] Custom a DatePipe to support special time zone conversion from user

    It didn\\\'t use a time zone format of datetime in database, data has only one time zone.    So I\\\'ll define a custom DatePipe to extend DatePipe in my source code of Angular. a. Component   providers: [MyDatePipe],   imports: [MyDatePipe] b. Html

    2024年02月11日
    浏览(27)
  • Which programming language do you choose

    NO.1:JavaScript JavaScript,简称JS语言,是一种具有函数优先的轻量级,解释型或即时编译型的高级编程语言。虽然它是作为开发Web页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和

    2024年02月02日
    浏览(29)
  • XFF漏洞利用([SWPUCTF 2021 新赛]Do_you_know_http)

    User-Agent:使得服务器能够识别客户使用的操作系统,浏览器版本等.(很多数据量大的网站中会记录客户使用的操作系统或浏览器版本等存入数据库中) Cookie:网站为了辨别用户身份进行session跟踪,并储存在用户本地终端上的数据(通常经过加密) X-Forwarded-For:简称XFF头,

    2024年02月09日
    浏览(30)
  • CTF 全讲解:[SWPUCTF 2021 新生赛]Do_you_know_http

    项目 描述 搜索引擎 Bing 、 Google AI 大模型 文心一言 、 通义千问 、 讯飞星火认知大模型 、 ChatGPT MDN Web Docs https://developer.mozilla.org/zh-CN/ 项目 描述 HackBar 1.2.2 浏览器 Chrome 项目 描述 得分项 HTTP 请求头 题目来源 NSSCTF 雾现 访问题目首页 hello.php 得到如下界面: 意在希望我们使

    2024年02月08日
    浏览(32)
  • java.sql.SQLException: Statement.executeQuery() cannot issue statements that do not produce result

    看看自己的java代码里的 sql语句的 select是不是写错了!   我把select写成了 selsct !!!!  

    2024年02月11日
    浏览(35)
  • Caused by: java.sql.SQLException: Statement.executeQuery() cannot issue statements that do not produ

    在用Spring Boot JPA的时候, 导致异常: Caused by: java.sql.SQLException: Statement.executeQuery() cannot issue statements that do not produce result sets. 解决方法: 在 @Query 上加上 @Modifying ,表示不需要返回值 这是因为,根据Spring data jpa官网 Doing so triggers the query annotated to the method as an updating query in

    2024年02月12日
    浏览(41)
  • docker报错:You have to remove (or rename) that container to be able to reuse that name

    You have to remove (or rename) that container to be able to reuse that name 错误原因:您必须删除(或重命名)该容器才能重用该名称。 解决: 查看docker 启动进程 杀死指定进程:

    2024年02月04日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包