function withMacroTask (fn) {
  return fn._withTask || (fn._withTask = function () {
    useMacroTask = true;
    try {
      return fn.apply(null, arguments)
    } finally {
      useMacroTask = false;    
    }
  })
}
Wrap a function so that if any code inside triggers state change,
the changes are queued using a (macro) task instead of a microtask.