OK, I'll address the new summary of your question in your comments (you should probably edit your question to just say this):
I want to run a piece of code on a future iteration of the event loop in the most efficient way (and let the current method return). No particular preferences, but but the order of continuations should matter. E.g., in my example, if property1 changed, then property2 changed, I first want propertyChanged be fired for property1, then for property2 (in both cases, asynchronously to the code that changed both properties).
The short version is you can use pretty much any of the options below to solve your issue. Without knowing more about your specific situations/requirements, I would probably recommend setImmediate() because it can't starve the event queue if triggered recursively, but either process.nextTick() or Promise.resolve().then() will trigger sooner (before other types of events) if that matters to your caller.
Here's some explanation of each choice - each will likely fulfill your objective, but each differs in some details.
All of these options allow the current tick of the event loop to finish and then they schedule a callback to be called on a future tick of the event loop. They differ in exactly when the next callback will be called and some will vary when they schedule the next callback based upon what type of event is currently be processed (e.g. where the event loop is in it's process of scanning several different event queues).
You can start by reading this overview article The Node.js Event Loop, Timers, and process.nextTick()
process.nextTick(cb)
This is the soonest way to schedule the callback. The current tick of the event loop finishes its execution and then before the node.js event loop code looks at any other event queues in the event loop, it looks for items in the nextTickQueue and runs them. Note, it is possible to "starve" the event loop if you are continually calling process.nextTick() recursively because it does not give other events a chance to run until the nextTickQueue is empty. This is not a "fair" scheduler.

setImmediate(cb)
This schedules a callback to be run after the current "phase" of the event loop is finished. You can think of the event loop as cycling through a number of different types of queues. When the current type of queue that is being processed is empty, then any pending setImmediate() callbacks will get processed.
Note, how this relates to other types of events, then depends upon what type of event was processing when setImmediate() was called.
As an example, if you were in the completion callback from fs.read() and you called setImmediate() to schedule a callback, then the event loop would first process any other pending I/O events before processing your setImmediate() callback. Because it doesn't get called until the event loop advances to the next type of event in the event queue, you can't starve the event loop with setImmediate(). Even recursively call setImmediate() will still cycle through all events.
How a pending setTimeout() is processed relative to a setImmediate() that you schedule depends upon what phase of the event loop you were in when you called the setImmediate(). This is generally beyond the scope of what you should be aware of in your code. If relative timing of multiple async operations like this is important, then you are much safer to just write code that guarantees a given sequence regardless of exactly when they operation is enabled by its callback. Promises can help you sequence things like this.
setTimeout(cb, 0)
Timers are one phase of the event loop. As it goes around the event loop looking at different types of event queues, one of the stages is to look for any timer events whose time has passed and thus it is time to call their callback. Because of this timers only run when the event loop is in the "timer phase" so how they fire relative to other types of events is indeterminate. It depends upon where the event loop is in its cycle when the timer is ready to go. Personally, I generally don't use setTimeout(cb, 0) unless I'm trying to synchronize with other timer events as this will guarantee a FIFO order with other timer events, but not with other types of events.
Promise.resolve().then(cb)
To get to this level of detail for promises (which you normally don't need to), you have to be very aware of what the promise implementation you are using is and how it works. A non-native-code promise implementation will use one of the other timing mechanisms to schedule its .then() handlers. Any of them can appropriately meet the Promise specification so they can vary.
Native promises in node.js do have a specific implementation. Personally, I know of no reason why you should write code that depends upon this specific implementation, but lots of people seem to be curious so I'll explain.
You can see a good diagram in this article: Promises, nextTicks and setImmediates. Native promises are implemented using what's called a micro tasks queue. It's essentially another queue like the nextTick queue that is processed after the nextTickQueue, but before any of the other queues. So, queued up .then() or .catch() handlers run immediately after and nextTick calls that are already scheduled and before any other types of events (timers, I/O completion, etc...).

Non-native promise implementations (like Bluebird or Q) don't have the ability to make a new microTasks queue that is processed after the nextTick queue so they use setImmediate() or process.nextTick().