code: 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);
  }
docs: 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