Await for deferred frame

Godot Version

4.2

Question

I have the current gdscript pseudocode:

func do_a():
  # Do stuff here.
  do_b.call_deferred()

func do_b():
  # Do some more stuff here, but at the end of the frame

This is working for me, but I don’t like how my logic is split in half. The first bit I need to happen at the start of the frame, then the next bit needs to happen at the end of this frame. I was hoping this could be simplified with await, something like below:

func do_stuff():
  # Do stuff here at start of frame.
  await <something idk>
  # Do some more stuff here, but at the end of the frame

But I don’t know what would be put in the triangle brackets. I know it needs a signal, but not sure how to give a signal that emits in the deferred update, assuming that’s possible.

await get_tree().process_frame should work I think.

I’m not sure when the process_frame signal is emitted exactly compared to when all the call_deferred stuff is called, but it’s sometime before _process() is called for the next frame…

No, I don’t think this is it, that signal will emit on the next frame, not the current one. I want a signal that emits at the end of this frame, similar to how call_deferred works. Perhaps the signal you suggested calls before the next frame’s code runs, but I do want it to happen on this frame to avoid any visual stuttering.

I tried creating the following function which seemed promising:

func wait_deferred() -> Signal:
	var deferred_signal := Signal(self, "deferred")
	deferred_signal.emit.call_deferred()
	return deferred_signal

func something():
	await wait_deferred()

but this throws an error:

Attempt to connect nonexistent signal 'deferred' to callable

What do you do to define a signal? There’s also the create_user_signal function, however I don’t see any way to get a reference to said signal for use with the await keyword

Aha got it, for anyone else who needs it:

signal deferred

func wait_deferred() -> Signal:
	var deferred_signal := Signal(deferred)
	deferred_signal.emit.call_deferred()
	return deferred_signal

func do_something():
	# Stuff happens here
	await wait_deferred()
	# Stuff happens here at the end of the current frame

The key was to define a signal, then make duplicates of it when needed. I’m not sure how to make signals from scratch at runtime…