feat(zone.js): monkey patches queueMicrotask() (#38904)

Close #38863

Monkey patches `queueMicrotask()` API, so the callback runs in the zone
when scheduled, and also the task is run as `microTask`.

```
Zone.current.fork({
  name: 'queueMicrotask',
  onScheduleTask: (delegate: ZoneDelegate, curr: Zone, target: Zone, task: Task) => {
    logs.push(task.type);
    logs.push(task.source);
    return delegate.scheduleTask(target, task);
  }
}).run(() => {
    queueMicrotask(() => {
      expect(logs).toEqual(['microTask', 'queueMicrotask']);
      expect(Zone.current.name).toEqual('queueMicrotask');
      done();
  });
});

```

PR Close #38904
This commit is contained in:
JiaLiPassion 2020-09-19 14:10:32 +09:00 committed by Misko Hevery
parent 6138bc2774
commit 27358eb60f
5 changed files with 74 additions and 3 deletions

View File

@ -4,7 +4,7 @@
"uncompressed": {
"runtime-es2015": 1485,
"main-es2015": 140899,
"polyfills-es2015": 36571
"polyfills-es2015": 36964
}
}
},
@ -22,7 +22,7 @@
"uncompressed": {
"runtime-es2015": 1485,
"main-es2015": 146698,
"polyfills-es2015": 36571
"polyfills-es2015": 36964
}
}
},
@ -31,7 +31,7 @@
"uncompressed": {
"runtime-es2015": 1485,
"main-es2015": 136062,
"polyfills-es2015": 37392
"polyfills-es2015": 37641
}
}
},

View File

@ -25,6 +25,15 @@ Zone.__load_patch('legacy', (global: any) => {
}
});
Zone.__load_patch('queueMicrotask', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
api.patchMethod(global, 'queueMicrotask', delegate => {
return function(self: any, args: any[]) {
Zone.current.scheduleMicroTask('queueMicrotask', args[0]);
}
});
});
Zone.__load_patch('timers', (global: any) => {
const set = 'set';
const clear = 'clear';

View File

@ -294,6 +294,34 @@ interface ZoneGlobalConfigurations {
*/
__Zone_disable_requestAnimationFrame?: boolean;
/**
*
* Disable the monkey patching of the browser's `queueMicrotask()` API.
*
* By default, `zone.js` monkey patches the browser's `queueMicrotask()` API
* to ensure that `queueMicrotask()` callback is invoked in the same zone as zone used to invoke
* `queueMicrotask()`. And also the callback is running as `microTask` like
* `Promise.prototype.then()`.
*
* Consider the following example:
*
* ```
* const zone = Zone.current.fork({name: 'myZone'});
* zone.run(() => {
* queueMicrotask(() => {
* console.log('queueMicrotask() callback is invoked in the zone', Zone.current.name);
* // Since `queueMicrotask()` was invoked in `myZone`, same zone is restored
* // when 'queueMicrotask() callback is invoked, resulting in `myZone` being console logged.
* });
* });
* ```
*
* If you set `__Zone_disable_queueMicrotask = true` before importing `zone.js`,
* `zone.js` does not monkey patch the `queueMicrotask()` API and the above code
* output will change to: 'queueMicrotask() callback is invoked in the zone <root>'.
*/
__Zone_disable_queueMicrotask?: boolean;
/**
*
* Disable the monkey patch of the browser blocking APIs(`alert()`/`prompt()`/`confirm()`).

View File

@ -0,0 +1,33 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ifEnvSupports} from '../test-util';
describe(
'queueMicrotask', ifEnvSupports('queueMicrotask', function() {
it('callback in the queueMicrotask should be scheduled as microTask in the zone',
(done: DoneFn) => {
const logs: string[] = [];
Zone.current
.fork({
name: 'queueMicrotask',
onScheduleTask: (delegate: ZoneDelegate, curr: Zone, target: Zone, task: Task) => {
logs.push(task.type);
logs.push(task.source);
return delegate.scheduleTask(target, task);
}
})
.run(() => {
queueMicrotask(() => {
expect(logs).toEqual(['microTask', 'queueMicrotask']);
expect(Zone.current.name).toEqual('queueMicrotask');
done();
});
});
});
}));

View File

@ -29,3 +29,4 @@ import './mocha-patch.spec';
import './jasmine-patch.spec';
import './browser/messageport.spec';
import './extra/cordova.spec';
import './browser/queue-microtask.spec';