The reason, of course, is that so long as the tiddler with the button is rendered, on every change, the core will need to reevaluate the nested lists, both quite long.
If you move the activity into a procedure, and call that procedure as the action parameter of your button, you will only evaluate the lists on click:
\procedure delete-fields()
<$list filter="[all[tiddlers]]" variable="tiddlername">
<$list filter="[fields[]] -title -text -type -tags -created -author -modified -library -url -caption -status -list -version -plugin-priority -name -description -dependents -core-version -plugin-type -current-tiddler library_version -collection -modifier -creator -source -filter -revision -bag -list-after -pretitle -posttitle -icon -var -draft.title -draft.of -color" variable="fieldname" tiddler=<<tiddlername>>>
<$action-deletefield $tiddler=<<tiddlername>> $field=<<fieldname>> />
</$list>
</$list>
\end delete-fields
<$button actions=<<delete-fields>> > delete fields</$button>
And I finally realize the reason experienced people have been pushing “action strings”! These delay rendering of the contents of the button until its actually needed. Sometimes I can be dense, I guess.
For the list of fields to delete, you might look at an earlier discussion about this. I was pretty happy to come up with this filter:
[fields[]] -[all[shadows]removeprefix[$:/language/Docs/Fields/]]