I think this goes against the idea of signals: Emit upwards in the hierarchy, and don't worry about whether it's listened for. I think there are ways around this if you know how many other nodes are listening for the signal.
But I'm implementing the following hack for this:
I have an internal signal called something like
signal_handled, and then my child node looks like this:
@export var number_of_signal_handlers: int = 3
func on_button() -> void:
for i in number_of_signal_handlers:
# Whatever you want to happen after the signal handlers have finished.
And my listeners look like this:
onready var child_node
func _ready() -> void:
func _handle_signal() -> void:
# Do whatever you want here
It's obviously a fragile solution that's prone to issues, but in my specific case there's only one thing listening to the signal and calling the child node's internal signal.
I think this is kinda in keeping with the idea of coroutines, where control is passed back and forth in the form of 'cooperative concurrency'.