-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
autorun can cascade through zone.run() #140
Comments
Good point. Ideally though, it would be checking if it's already running in the zone. |
Fair point, although I'm not sure about the performance benefit. But I guess we could do something like this._zone.onTurnStart.subscribe(() => this._inZone = true)
this._zone.onTurnDone.subscribe(() => this._inZone = false)
...
if (autoBind) {
hAutorun = Tracker.autorun(() => {
func();
if (!this._inZone) {
Tracker.afterFlush(() => {
this._zone.run(() => {});
});
}
});
} Want a PR or will you fix? |
By the way...shouldn't |
It may not work if Did you test it? If zone is checked we don't need Tracker.afterFlush any more, I guess. |
What I interpret your comment as is to do: func();
if (!this._inZone) {
this._zone.run(() => {});
} Well, the way I see it we still need I tried my code with zone checking above. I was never in zone. I tried it again with the // Static
let pendingTrackerFlush = false;
...
Tracker.autorun(() => {
func();
if (!this._inZone && !pendingTrackerFlush) {
pendingTrackerFlush = true;
Tracker.afterFlush(() => {
this._zone.run(() => {
pendingTrackerFlush = false;
});
});
}
}); Now, another problem is A middle ground might be to have the |
Ok, I am back to this issue. Sorry, other stuff took some time.
Could you elaborate what issue you are facing exactly with this? |
Sure, that construction is possible and useful. My problem is with unintentional cascading as a side effect of running
What we want is leaving the autorun as soon as // static
let pendingRuns = new Set<Zone>();
const rootZone = Zone.current;
// patched Tracker.autorun
autorun(cb) {
capZone = Zone.current;
return Tracker.autorun(() => { // Unpatched
if (Zone.current === capZone) {
// This minimizes a tick as we'll get one tick "for free" and don't have a run() call finishing
cb();
} else {
pendingRuns.add(Zone.current);
rootZone.run(cb);
rootZone.scheduleMacroTask(() => {
const s = pendingRuns;
if (s.size) {
pendingRuns = new Set<Zone>();
s.forEach(z => z.run(() => {}));
}
})
}
})
} |
@staeke right it seems to have sense. but why not then just |
Well, in the case where you are already in the right zone you avoid one tick. If the other case (I guess that's the one you meant), my code basically throttles all tick requests down to one. Just calling setTimeout wouldn't. It's quite typical that a lot of autoruns fire because of one change. It would be unfortunate to get ~100 tick requests (we've seen such cases). If, however you mean checking if a timeout has been scheduled and then not schedule one, yeah I guess that would work. But since multiple Angular applications may be running you need to store onr flag per angular zone. |
I am not sure that scheduleMacroTask can do that throttling you mentioned w/o |
Probably was unclear. No, As for the component approach vs. patching
...since these methods may all results in callbacks being called as a result of server operations, and thus DDP/websocket callbacks outside any angular zone. Since we need to patch all these methods, I think it makes more sense to patch the general API rather than to require a component base class. Component base classes limits quite actively where you could safely use Meteor. You may for instance want to do it in services. Also, I think it makes sense to make it really hard to do anything wrong. I see this work as making Meteor "compatible" with zone js, not Angular per se. There is still utility for a Do you agree? |
Global patching is certainly not elegant solution, also I tend to think that user can take care of himself. So I would rather extend, for example, |
Thanks for your reply Alex, Elegant or not, that's the path Anyhow, even if you don't want to patch, it seems a wrapper/façade would be a more reasonable approach (with the annotation for automatic disposal of handles), as then it can be used from any code (not just components). Also annotations and base classes limit their use to TypeScript - some people prefer just plain javascript. |
I agree patching Meteor methods makes sense but in general (i.e., relatively to global zone for the sake to have good stack traces). There was a package actually that does it on Atmosphere. But we want here something more specific, i.e., running in Angular2 zones per app and with throttling, |
Currently, calls like
this.autorun(..., true)
can cascade. By that I mean that thezone.run(...)
call can synchronously lead to components being created, initialized and thus other autoruns to be run. But...this is depending on context and how/when the first autorun is run. The consequence if/when this happens is that Tracker is in a computation when thezone.run
kicks off change detection. Further autorun calls will just add to the current computation, although all "user code" has already completed. I suggest a change to something likeCan make a PR if you agree
The text was updated successfully, but these errors were encountered: