我想在我的Angular项目中使用zone.js(而不仅仅是runOutsideAngularZone函数)。
我试图这样包含它:
import { zone } from 'zone.js';
不幸的是,我收到此错误:
error TS2306: File 'C:/projects/MyApp/node_modules/zone.js/dist/zone.js.d.ts' is not a module.
然后我删除了{ zone }
部分:
import 'zone.js';
但是现在我收到此错误:
error TS2552: Cannot find name 'zone'. Did you mean 'Zone'?
我的代码是这样的:
let myZoneSpec = {
beforeTask: function () {
console.log('Before task');
},
afterTask: function () {
console.log('After task');
}
};
let myZone = zone.fork(myZoneSpec);
myZone.run(() => {console.log('Task');});
如果我将żone
替换为Zone
,我会得到:
error TS2339: Property 'fork' does not exist on type 'ZoneType'.
如何从Angular导入和使用zone.js?
答案 0 :(得分:4)
Angular为 Zone.js 提供了一个包装类,称为 ngZone 。您可以像任何服务一样将其注入到组件中。
constructor(private zone: NgZone) {
this.zone.run(() => { console.log('This is zone'});
}
但是,通过这种方法,我们无法使用 zone.js 的全部功能。为此,我们必须声明:
declare let Zone: any;
public class MyComponent {
constructor() {
Zone.current.fork({
name: 'myZone'
}).run(() => {
console.log('in myzone? ', Zone.current.name);
});
}
}
此外,自v.0.6.0起,API也已更改。对于运行beforeTask和afterTask,您可以查看它here,但是,我调查了一下,但是找不到与 beforeTask 和 afterTask 相关的任何内容。 / p>
已更新
对于运行 beforeTask 和 afterTask ,这是在新API中的方法。
constructor() {
const parentZone = new Zone();
const childZone = parentZone.fork({
name: 'child',
onInvoke: (...args) => {
console.log('invoked\n', args);
const valueToReturn = args[3](); // Run the function provided in the Zone.run
console.log('after callback is run');
return valueToReturn;
}
});
console.log(childZone.run(() => {console.log('from run'); return 'from child run';}));
}
注意:
如果您想创建一个 scheduleMicroTask 并希望其中也具有相同的功能,则需要在其中实现 onInvokeTask 和/或 onScheduleTask ZoneSpec(在parentZone.fork()内部)。
constructor() {
const parentZone = new Zone();
const childZone = parentZone.fork({
name: 'child',
onScheduleTask: (...args) => {
console.log('task schedule...\n', args);
return args[3];
},
onInvokeTask: (...args) => {
console.log('task invoke...\n', args);
return args[3].callback();
}
});
const microTask = childZone
.scheduleMicroTask(
'myAwesomeMicroTask',
() => {
console.log('microTask is running');
return 'value returned from microTask';
} );
console.log(microTask.invoke());
}
答案 1 :(得分:0)
我强烈建议您在Angular中使用NgZone。 Documentation here
答案 2 :(得分:0)
有几种解决方案可以拦截异步任务,其中一种解决方案是创建自己的区域。
通过Zone.prototype.run
输入应用程序也会在您的区域中进行引导。
可以使用Zone.prototype.fork
方法创建自己的区域,fork
-创建一个子区域,实际上复制父区域,复制的区域成为后代:
const customZone = Zone.current.fork({
name: 'customZone'
});
name
是区域的名称,您可以指定任何字符串,这是唯一必需的参数。 fork
接受名为ZoneSpec
的对象。它允许您指定一堆方法来拦截任何异步作业的生命周期。生命周期为-schedule -> do synchronous things -> execute at the right time
。
ZoneSpec
接口允许实现此类挂钩:
onFork
-钩子拦截子区域的创建onInvoke
-钩子以拦截Zone.prototype.run
onHandleError
-错误处理挂钩onScheduleTask
-拦截任务调度,例如调用setTimeout
调度宏任务onInvokeTask
-拦截异步API中的回调,例如,当调用setTimeout
中的回调时onCancelTask
-拦截任务或结束的取消onHasTask
-每次队列更改时调用回到您的问题:
我想在每个任务之前和之后调用一个函数。这就是为什么我想使用区域
您可以创建区域并实现所需的挂钩,在这种情况下,您需要onInvokeTask
:
const customZone = Zone.current.fork({
name: 'customZone',
onInvokeTask(
parentZoneDelegate: ZoneDelegate,
currentZone: Zone,
targetZone: Zone,
task: Task,
applyThis: any,
applyArgs: any[]
) {
console.log('before task...'); // do your stuff before any task here...
const result = parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs);
console.log('after task...'); // do your stuff after any task here...
return result;
}
});
customZone.run(() => {
setTimeout(() => {
console.log('setTimeout callback...');
});
});
您将在控制台中看到:
before task...
setTimeout callback...
after task...
您还可以获取有关该任务所需的所有信息,例如我们只想在微任务之前和之后做一些事情:
const customZone = Zone.current.fork({
name: 'customZone',
onInvokeTask(
parentZoneDelegate: ZoneDelegate,
currentZone: Zone,
targetZone: Zone,
task: Task,
applyThis: any,
applyArgs: any[]
) {
const isMicroTask = task.type === 'microTask';
if (isMicroTask) {
console.log('before micro task...'); // do your stuff before any micro task here...
}
const result = parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs);
if (isMicroTask) {
console.log('after micro task...'); // do your stuff after any micro task here...
}
return result;
}
});
customZone.run(() => {
setTimeout(() => {
console.log('setTimeout callback...');
});
Promise.resolve().then(() => {
console.log('then callback...');
});
});
您将在控制台中看到:
before micro task...
then callback...
after micro task...
setTimeout callback...
或仅用于事件任务:
const isEventTask = task.type === 'eventTask';
// check if `eventTask` and do something only for event tasks
const result = parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs);
// check if `eventTask` and do something only for event tasks
return result;
如果“任何内容”都有通过addEventListener
添加的事件监听器,则此方法适用于浏览器添加到队列中的任务:
customZone.run(() => {
document.body.addEventListener('click', () => {
console.log('onClick callback...');
});
document.body.dispatchEvent(new KeyboardEvent('click'));
});
为了拦截Angular中的异步任务-您需要使用Zone.prototype.run
包装应用程序自举:
const customZone = Zone.current.fork({
name: 'customZone',
onInvokeTask(
parentZoneDelegate: ZoneDelegate,
currentZone: Zone,
targetZone: Zone,
task: Task,
applyThis: any,
applyArgs: any[]
) {
console.log('before task...');
console.log('task = ', task);
const result = parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs);
console.log('after task...');
return result;
}
});
customZone.run(() => {
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(error => console.error(error));
});
您还可以通过提供自定义NgZone.prototype.run
来拦截ApplicationRef.prototype.tick
和this._zone.run(() => this.tick())
(因为它们被NgZone
包裹)调用:
if (environment.production) {
enableProdMode();
}
class CustomNgZone extends NgZone {
run<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T {
// do something before the callback is invoked
const result = super.run(fn, applyThis, applyArgs);
// do something after the callback is invoked
return result;
}
}
const ngZone = new CustomNgZone({ enableLongStackTrace: isDevMode() });
platformBrowserDynamic()
.bootstrapModule(AppModule, { ngZone })
.catch(error => console.error(error));
请注意,由于CustomNgZone
的调用将锁定Angular的全局变量(enableProdMode
),因此我将在isDevMode
之后创建_runModeLocked = true
类的实例,因此生产函数将不使用。