function doWhilst(iteratee, test, callback) {
        callback = onlyOnce(callback);
        var _fn = wrapAsync(iteratee);
        var _test = wrapAsync(test);
        var results;

        function next(err, ...args) {
            if (err) return callback(err);
            if (err === false) return;
            results = args;
            _test(...args, check);
        }

        function check(err, truth) {
            if (err) return callback(err);
            if (err === false) return;
            if (!truth) return callback(null, ...results);
            _fn(next);
        }

        return check(null, true);
    }
The post-check version of [`whilst`]{@link module:ControlFlow.whilst}. To reflect the difference in
the order of operations, the arguments `test` and `iteratee` are switched.

`doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.

@name doWhilst
@static
@memberOf module:ControlFlow
@method
@see [async.whilst]{@link module:ControlFlow.whilst}
@category Control Flow
@param {AsyncFunction} iteratee - A function which is called each time `test`
passes. Invoked with (callback).
@param {AsyncFunction} test - asynchronous truth test to perform after each
execution of `iteratee`. Invoked with (...args, callback), where `...args` are the
non-error args from the previous callback of `iteratee`.
@param {Function} [callback] - A callback which is called after the test
function has failed and repeated execution of `iteratee` has stopped.
`callback` will be passed an error and any arguments passed to the final
`iteratee`'s callback. Invoked with (err, [results]);
@returns {Promise} a promise, if no callback is passed