Output
The 'finally' clause of your ComfyUI batch loop
- output_list
Output (class AsyncOutputCallback) is where the AsyncOutput family actually pays off. The Collection node has been stashing strings into a list for N runs; the Emitter has been counting; and this node is the Promise.all(...).then(...) - the callback that finally receives the whole list and hands it to the rest of your graph.
But it's also the node that explains how this pack does "conditional execution," which is the part beginners bounce off. The trick is comfy_execution.graph.ExecutionBlocker. ComfyUI has no if statement, but a node can return an ExecutionBlocker instead of a real value, and ComfyUI then skips everything downstream of it for that pass. That's not an error - the run continues, the other branches still execute, only the blocked branch stands down. Callback returns a blocker whenever emitter_result is false, meaning "the batch isn't done yet, don't run the join step." The README states it plainly: if the received value is false, "the subsequent downstream process will be blocked directly."
How it works
On every pass it looks at emitter_result. False → ExecutionBlocker, downstream doesn't run. True → it pulls ASYNC_OUTPUT_STORAGE_DATA[key_id] (the accumulated list), returns it as output_list, and deletes the record so a later run can collect fresh. If the key_id has no data at all, it blocks too rather than erroring.
The inputs that matter
emitter_result(BOOLEAN, forced input) - wire this from an AsyncOutputEmitter'semit_resultoutput. That's the whole signal.key_id(STRING) - must match the Collection and Emitter you're working with. Same key or nothing lines up.reset(BOOLEAN, optional) - deletes the stored list for this key and blocks. Handy for clearing a collection mid-run.
Output: output_list (LIST) - the accumulated strings, in the order the Collection nodes appended them. Feed it into a join node, a "String List To String" converter, or anything else that eats a LIST.
Installing it
Zero dependencies, no model files. ComfyUI Manager → search "AsyncOutput" → install, or:
cd ComfyUI/custom_nodes
git clone https://github.com/teddy1565/ComfyUI-AsyncOutput
Restart. It lives under AsyncOutput/Deprecated(ComfyUI NOT Turing complete)/String.
Where people get burned
Two gotchas, both worth memorizing. First, if you see downstream nodes "just not running" with no error, that's the blocker doing its job - check whether emitter_result is actually true that pass. Second, the data is deleted after read: if your workflow re-executes the callback later in the same run (say, a second pass hits it), there's nothing left and it blocks. That's by design - this is a one-shot gather, not a persistent buffer.
And the standing caveat that applies to the whole pack: the author marks the AsyncOutput family deprecated because ComfyUI isn't really Turing-complete in the way this pattern wants it to be. All the shared state lives in process memory, gets auto-wiped at the start of each run by default, and disappears on restart. For a one-run batch loop it's fine. For anything you expect to remember its own history, look at the non-deprecated BatchIteratorStringCallback, which does the same gather - but notably does not delete the data after reading it.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| emitter_result | BOOLEAN | — | |
| key_id | STRING | — | |
| resetopt | BOOLEAN | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| output_list | LIST | — |