问题
The custom component
I've created a custom component for the navigation of my app. It consists of an ul
element and all its li
elements are dynamically created based on the items in the router's navigation list. This is happening in the attached event of the component. Nothing special is going on here.
The custom attribute
But because I want to have a good looking fancy menu I also created a custom attribute and implemented it into the root ul
element of the custom component. In the attached
event of the custom attribute I'd like to do some dom
manipulations so that my menu looks like a menu created by those cool kids.
The problem
Although the attached
event of the custom attribute is fired AFTER the attached
event of the custom component, the dynamically created li
items are not part of the dom in the attached
event of the custom attribute yet.
The question
My assumption was that on attached
event the view
of the actual component is attached to dom and that all components before are also attached to the dom. And when I am done with the attached
event the html that has been dynamically created here is also attached. Am I mistaken?
On a side note
I am aware of using TaskQueue
could solve my problem. However, I would like to know if there's a different approach/solution first because I believe that moving things in time could cause a chain of paradoxes leaving you in a maintenance nightmare.
回答1:
Allow me take away your misconception about the TaskQueue.
Your idea of moving things in time causing maintenance issues would certainly apply to using setTimeout()
because that incurs an actual delay, and forces execution onto the next event loop. queueTask()
is more or less the same thing (it uses setTimeout()
internally).
However, the TaskQueue's queueMicroTask()
method works very differently.
When you call queueMicroTask()
, unlike queueTask()
and setTimeout()
, the task is scheduled for immediate execution on the same event loop. This is a very robust mechanism with a guaranteed execution order, and it's generally considered good practice to use it within attached()
before doing any DOM manipulation.
In fact, queueMicroTask()
is used internally by Aurelia in various places (mostly in binding
and templating-resources
). Two notable places are:
- Property- and collection observers use it to "delay" notifying subscribers until all other bindings have completed their internal updating work
- The
repeat
attribute uses it to set anignoreMutations
flag (and unset it after the queue is flushed) to prevent infinite recursion while updating its inner collection
You can generally consider there to be two "phases" to the bind() and attached() hooks: a non-queued, and a queued phase. The queued phase is when components do work that relies on the whole component graph to first be done with some other (usually recursive) process.
queueMicroTask()
does not delay execution, just pushes it to the end of the call stack
It's the functional equivalent of passing the function as a callback to the end of the call stack, but saves you the trouble of writing the spaghetti code required to locate that last call and wire it all up. It's super clean.
all its li elements are dynamically created based on the items in the router's navigation list. This is happening in the attached event of the component
See, whenever you create anything during attached()
, you can't rely on that thing being there during another component's attached()
as this depends on the order of compilation/composition. That's an internal matter. This is especially true for custom attributes. Custom attributes (particularly those in style libraries) use the TaskQueue all over the place because it's the only way they can rely on the DOM being done.
Using queueMicroTask()
here will guarantee two things:
- It's executed when aurelia is completely done with the "first pass" of attacheds and rendering
- It's executed immediately when aurelia is done with that - not even a microsecond delayed.
The best (and perhaps only correct) way to address this is indeed by using the TaskQueue - I promise :)
来源:https://stackoverflow.com/questions/48596232/custom-attribute-attached-event-too-early