Apologies if this has been mentioned before -- I am further behind than usual in reading the forum.
When possible, I avoid using global variables by attaching state information to each message. I recently built a flow with some complex logic that was not producing the messages I expected in certain cases. Using a complete node attached to a debug node, I could catch the messages as they passed through each function and change node in the flow and so was able to see each message as it was modified at various points and find the problem.
This flow gives the general idea:
[{"id":"618b1cf1.6df17c","type":"inject","z":"42e9cb90.fa9734","name":"inject","topic":"testing complete node","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":280,"wires":[["d6ea6b13.304ce8","ed2f9d3d.1bcef8"]]},{"id":"17d0a463.499f2c","type":"debug","z":"42e9cb90.fa9734","name":"function output","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":460,"y":260,"wires":[]},{"id":"fa3c7acb.30e618","type":"complete","z":"42e9cb90.fa9734","name":"","scope":["d6ea6b13.304ce8","ed2f9d3d.1bcef8"],"uncaught":false,"x":110,"y":360,"wires":[["1d04b428.2c777c"]]},{"id":"1d04b428.2c777c","type":"debug","z":"42e9cb90.fa9734","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":250,"y":360,"wires":[]},{"id":"d6ea6b13.304ce8","type":"change","z":"42e9cb90.fa9734","name":"","rules":[{"t":"set","p":"time","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"topic","tot":"msg"},{"t":"set","p":"foo","pt":"msg","to":"bar","tot":"str"},{"t":"set","p":"topic","pt":"msg","to":"change node output","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":280,"y":300,"wires":[["c90a3799.49fe6"]]},{"id":"ed2f9d3d.1bcef8","type":"function","z":"42e9cb90.fa9734","name":"dummy function","func":"\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":260,"wires":[["17d0a463.499f2c"]]},{"id":"c90a3799.49fe6","type":"debug","z":"42e9cb90.fa9734","name":"change output","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":460,"y":300,"wires":[]}]
Before making a habit of this, I have a few questions:
- Are there obvious down sides to using 
completeas a debugging tool in this way? - Is this behavior likely to change in the future?
 - Are there core nodes in addition to 
function,change, anddebugthat have implemented thedone()function? - Would it be possible to add 
done()to other core nodes that transmit messages, likelink,delay, andtrigger, or that generate messages likeinject,rangeandrandom? 
Also, a couple of observations, illustrated by this flow:
[{"id":"c39db174.4b3d2","type":"complete","z":"f953caa6.ca00c","name":"","scope":["119e8e79.9e8012","171cafbb.ddde5","b1af9e2c.05fcc8"],"uncaught":false,"x":150,"y":240,"wires":[["8b9484f6.1ad448"]]},{"id":"5a2dbdb6.575ee4","type":"inject","z":"f953caa6.ca00c","name":"","topic":"empty function and debug","payload":"hello world","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":140,"wires":[["171cafbb.ddde5","119e8e79.9e8012","b1af9e2c.05fcc8"]]},{"id":"119e8e79.9e8012","type":"debug","z":"f953caa6.ca00c","name":"empty debug","active":false,"tosidebar":false,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":310,"y":140,"wires":[]},{"id":"171cafbb.ddde5","type":"function","z":"f953caa6.ca00c","name":"empty function","func":"","outputs":0,"noerr":0,"x":320,"y":100,"wires":[]},{"id":"8b9484f6.1ad448","type":"debug","z":"f953caa6.ca00c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":290,"y":240,"wires":[]},{"id":"b1af9e2c.05fcc8","type":"function","z":"f953caa6.ca00c","name":"function (no output)","func":"msg.payload = \"goodbye world\"\nmsg.topic = \"not empty function\"\nmsg.foo = \"bar\"","outputs":0,"noerr":0,"x":330,"y":180,"wires":[]}]
- Both the 
functionanddebugnodes will send a message to thecompletenode even when they do nothing to the input message and have no output. - The function node can modify the message sent to the 
completenode even when it has no output. - If the 
completenode is allowed to catch output from its attacheddebugnode, you get a loop.