Some thoughts on performance

If the issue is that the filtered transclusion output a link, why not assign the filter directly to the text widget or use another template for the filtered transclusion? Would that work too ?

.myclass [data-item-title="<$text text={{{ [{active}escapecss[]] }}}/>"] {
	color: #fff;
}

or

.myclass [data-item-title="{{{ [{active}escapecss[]]||$:/core/templates/canonical-uri-external-raw}}}"] {
	color: #fff;
}

Alternatively, a custom template with this content : 

<$view field="title"/>

The intent of my post is to point out a problematic code pattern to avoid, rather than to recommend a specific alternative.

There are several alternatives. The one I posted is a derivative of code I was working with where I needed to reference the output of the filter more than once and therefore a $let widget is a better choice than assigning directly to a $text widget.

Filtered transclusions are a poor choice in this scenario from a performance point of view, as previously stated the widget tree created is more complex. Not to mention that having to create or reference another template that you cannot see in situ is also going to be error-prone.

2 Likes

I see, that make sense. Thanks !

As of 17/03/2022 this no longer an issue in TW 5.2.2 pre-release. The CSS is only updated when it has changed, regardless of underlying widgets used in stylesheets.

1 Like

4 posts were split to a new topic: Reveal/list widget, performance and alternatives

I have moved the discussion on potential alternatives to $reveal/$list that are not present at this moment in the TiddlyWiki core into a separate topic. That should allow proper discussion of new ideas while keeping this topic focused on actionable advice pertaining to the core.

2 Likes

@saqimtiaz: How about defining variables using the \define pragma? How does that affect refreshing?
In particular, does it make a difference if I define a (sub)filter using

\define filter-definition() [ some filter definition goes here ]

lots of code goes here

<$list filter="[subfilter<filter-definition>]">
    more code goes here
</$list>

or

lots of code goes here

<$let filter-definition="[ some filter definition goes here ]">
    <$list filter="[subfilter<filter-definition>]">
        more code goes here
    </$list>
</$let>

Since the variable is basically just a constant string that never changes, I’d assume there’d be not much of a difference.
What about the case when filter-definition contains a variable reference so that it might change?

Have a nice day
Yaisog

@Yaisog apologies, I did not see your questions until now.

Of the widgets that assign variables, the $list widget is a special case. It only entirely re-renders itself and its contents if the attributes assigned to the widget change. If only the output of the filter changes, it is heavily optimised to try and re-use and move around as many of the existing items as possible (under the covers each list item is an $listitem widget).

With regards to the \define pragma, it defines a variable and as long as you are not doing any text substitution the performance should be identical to using the $let widget.

The $list widget will handle this well and try to refresh only the list items necessary.

However, other widgets like $let, $set, $vars will destroy themselves and their children and then recreate everything when the value of the variable assigned changes. This is because re-creating itself and the child widgets is the only way to propagate the new variable value.

One of the things that I have been experimenting with and still needs more work, is a technique using IntersectionObserver that suspends refresh for widgets that are not visible. There are edge cases where this is causing issue but the performance gains are considerable with large or complex layouts.

@saqimtiaz: Thanks for your explanation.

Just to make sure I got all of this correct: In this code

lots of code goes here

<$let filter-definition="[ some filter definition goes here ]">
    <$list filter="[subfilter<filter-definition>]">
        more code goes here
    </$list>
</$let>

since the content assigned to filter-definition is just a (constant) string and not the filter result, this use of subfilter<filter-definition> will not result in the destruction of the $list (as a child of $let) when the actual result of the subfilter changes?

Also, pertaining to my initial question, you recommend not to put more content into $let than is necessary (because all of it is destroyed when the variable value changes). However, the scope of \define is the whole tiddler – so when the output of the macro changes, everything in the tiddler is destroyed and re-rendered?

Have a nice day
Yaisog

Correct.

Unless the \define is in another tiddler, I don’t see how it can change without re-rendering the entire tiddler anyway.

If the macro is defined in another tiddler and either global or imported using $importvariables then yes, any change in it will refresh the entire tiddler it is being imported into.

Keep in mind that macros return strings, i.e. the wikitext is not processed. So if you are not using string substitution in your macro, you never have to worry about it changing.