docs: function iterator(iterId, conn) {
        var nextElems = [];
        var done = false;
  
        function nextPromise() {
          var kv = nextElems.pop();
          return new Promise(function (fulfill, reject) {
            fulfill(f.merge({done: done}, kv));
          });
        }
  
        function donePromise() {
          return new Promise(function (fulfill, reject) {
            fulfill({done: done});
          });
        }
  
        return {
          /**
           * Iterator next object returned from completed Iterator.next() calls.
           *
           * @typedef {Object} IteratorNext
           * @property {?(String|Object)} key -
           * If iteration not done, entry's key, otherwise undefined.
           * @property {?(String|Object)} value -
           * If iteration not done, entry's value, otherwise undefined.
           * @property {Boolean} done -
           * Indicates whether iteration has been completed.
           * When true, key and value will be undefined.
           * When false, key and value will be non-null.
           * @since 0.3
           */
          /**
           * Returns the next entry being iterated over.
           *
           * @returns {module:promise.Promise.<IteratorNext>}
           * It returns a Promise which will be completed with an instance that
           * provides the next element.
           * @memberof Iterator#
           * @since 0.3
           */
          next: function() {
            if (done) {
              logger.tracef('Iterator(iteratorId=%s) already exhausted', iterId);
              return donePromise();
            } else if (_.isEmpty(nextElems)) {
              var ctx = u.context(SMALL);
              logger.tracef(
                  'Invoke iterator.next(msgId=%d,iteratorId=%s) on %s'
                  , ctx.id, iterId, conn.toString()
              );
              var remote = futurePinned(ctx, 0x33, p.encodeIterId(iterId), p.decodeNextEntries(), conn);
              return remote.then(function(entries) {
                if (_.isEmpty(entries)) {
                  done = true;
                  return donePromise();
                } else {
                  _.each(entries, function(entry) {
                    nextElems.push(entry);
                  });
                  return nextPromise();
                }
              });
            }
            logger.tracef('Return next from locally cached entries for iterator(iteratorId=%s)', iterId);
            return nextPromise();
          },
          /**
           * Close the iteration.
           *
           * @returns {module:promise.Promise}
           * A Promise which will be completed once the iteration has been closed.
           * @memberof Iterator#
           * @since 0.3
           */
          close: function() {
            var ctx = u.context(SMALL);
            logger.debugf('Invoke iterator.close(msgId=%d,iteratorId=%s) on %s', ctx.id, iterId, conn.toString());
            return futurePinned(
                ctx, 0x35, p.encodeIterId(iterId), p.complete(p.hasSuccess), conn);
          }
        }
      }