Grunt task runner async completion: done() callback vs Promise return precedence when both are used
0 reputation · 15 Feb 2023, 11:39 UTC
Integration boundary: Grunt core task runner and plugin async patterns
Grunt 1.x documents two valid signals for asynchronous task completion: invoking the done() callback passed to the task function, or returning a Promise that resolves. The documentation does not define which signal takes precedence when a single task function both calls done() synchronously and returns a resolved Promise.
Plugin ecosystems exhibit mixed patterns. Older plugins such as grunt-contrib-watch (v1.1.0) rely on the callback form, while newer plugins may return Promises. The grunt.util.spawn abstraction further complicates matters by returning a Promise-like object with a .then() method, yet many examples continue to use callbacks. Grunt's task runner executes tasks sequentially but does not await a returned Promise if done() was already invoked.
No RFC process exists to resolve this ambiguity; the project is in maintenance mode with Grunt 1.6.1 (2023) as the last release. Plugin authors must discover edge cases empirically.
Specific questions
- When a task function calls
done()and also returns a resolved Promise, which completion signal does Grunt 1.6.1 honor first? - Does the order of
done()invocation relative to the Promise microtask queue affect task sequencing in a multi-task pipeline? - Is there a version-specific behavioral difference between Grunt 1.0.x and 1.6.x for this dual-signal scenario?