我们的应用程序存在问题,而且很难确定。在这一点上,我相对确信在角度(或区域,或webpack,或角度cli)中存在某个错误,但复制所需的应用程序的复杂性使得它作为一个帖子发布时有点过高错误报告或插件。所以我想我会在这里发帖,希望有人可以提供一些能够应对类似挑战的洞察力。
我们正在加载的页面包含多个彼此交互的组件,但我会尽量保持对问题的描述尽可能简单。 OnInit,我们的组件进行异步调用以获取下拉列表的一些数据。在列表中选择项目时,将为第二组选项异步加载数据。选择其中一个时,将加载详细数据异步。当数据详细信息observable为详细信息对象发出新值时,我们将组件详细信息变量设置为新数据,并更新绑定到此变量的视图元素。
所描述的选项既可以一次手动选择一个,也可以作为路径参数传递。当路由参数提供时,一个接一个地自动处理选择,触发相同的异步调用序列,最终导致在视图中显示详细数据。
从rc1开始,我们一直在使用TypeScript 1.8从Visual Studio开发和构建,并使用SystemJS构建运行时模块加载器。但是我们最近开始准备发货,并决定尝试使用angular-cli捆绑我们的脚本并构建生产。 angular-cli构建利用webpack进行模块加载。
大多数情况下,一切都适用于cli构建,但我们看到调整更改检测的次数减少了。在我上面描述的情况中,这导致变化检测在我们加载应用程序时发生的一系列异步数据调用中间停止运行,我们将选项作为路径参数传入。我们可以在控制台中看到返回了详细数据,但是在某个点之后视图没有更新,即使绑定到模板元素的变量实际上已设置为新值。组件的更改检测器不会再次运行以获取更改。如果我们点击屏幕上的任意位置或执行其他触发更改检测器的操作,则视图会立即反映新数据。
角度模块和其他依赖项的所有版本都是最新的稳定版本,两个版本之间相同。但Visual Studio / SystemJS构建工作(并且似乎更频繁地基于来自ngDoCheck内部的调试语句运行更改检测方式),而angular-cli / webpack版本在检测到中途变化时停止。
我已经踩过微小角度和区域脚本的杂草大约两天试图看看有什么不同,但到目前为止还没有能够辨别为什么变化检测表现得很好如此不同。我可以通过使用组件代码中的setTimeouts和其他黑客来强制更改检测器运行来解决这个问题,但我真的很想理解为什么我必须首先执行此操作。任何人都可以提供的见解将不胜感激。
其他信息:
以下是组件订阅处理程序中的代码。我认为只有sub接收到一个新值的事实本身会导致变化检测,但由于这不起作用,我还在setTimeout中处理了新数据。在处理新数据的方法中,更新绑定到视图中元素的变量,我也认为应该触发更改检测,但不会。
fundsService.fundDetail$.subscribe(
(updatedDetails) => {
$log.debug('subscription received new data');
$log.debug('setting timeout. will handle new data inside timeout');
setTimeout(() => {
this.handleNewFundDetail(updatedDetails);
$log.debug('data set into vars bound to view. shouldn\'t change detection run now?');
});
},
(error) => {
$log.error('Error loading fund detail: ' + error.message);
this.dialogService.error('Error loading fund detail.');
}
)
从控制台日志中可以看出,在此之后,Visual Studio中构建的相同代码实际上会运行更改检测。事实上即使没有将数据处理方法包装在超时中也是如此。
但是当从角度cli构建运行时,在订阅中接收到新数据后没有变化检测,没有由setTimeout产生的变化检测,并且在模板绑定变量发生变化时没有变化检测。
那究竟发生了什么?为什么不改变检测点火?
更新:如果我在订阅中的另一个超时内嵌入超时,则更改检测运行。如果我只是在handleNewDetail之后添加超时,或者仅在handleNewDetail周围包装超时,则不会发生更改检测。但如果我像这样嵌套它,就会发生突然的变化检测。当然,做这样的事情是荒谬和随意的,在我们使用angular-cli构建应用程序之前不应该是必要的。 :/
service.detail$.subscribe(
(updatedDetails) => {
setTimeout(() => {
this.handleNewDetail(updatedDetails);
setTimeout(() => {
$log.debug('inception timeout inside a timeout');
//CHANGE DETECTION ACTUALLY HAPPENS
},100);
});
}
答案 0 :(得分:3)
将此作为angular-cli团队的一个问题打开,并被要求尝试删除polyfills.ts中的导入,而是通过index.html中的CDN下拉这些脚本,如此
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js@0.6.25?main=browser"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.3"></script>
这解决了变更检测的问题,但我仍然不确定原因。关注https://github.com/angular/angular-cli/issues/2752以获取更新。非常感谢角色团队的@filipesilva提供帮助。
更新:
此问题的更好解决方法是不需要从CDN中删除脚本或在index.html中单独链接它们是将它们添加到angular-cli.json中的脚本数组中。这将对这些文件进行所有捆绑,缩小和树形抖动,同时仍解决变更检测问题。我要添加的唯一警告是确保这些是数组中的第一个文件,如下所示:
"scripts": [
"../node_modules/core-js/client/shim.min.js",
"../node_modules/zone.js/dist/zone.js",
"../node_modules/reflect-metadata/Reflect.js",
"common/someOtherScript.js"
],