code: async function filter(array, fn, self = undefined) {
    const v = await Promise.resolve(array);
    if (!Array.isArray(v)) {
      throw TypeError('not an array');
    }
  
    const arr = /** @type {!Array} */(v);
    const n = arr.length;
    const values = [];
    let valuesLength = 0;
  
    for (let i = 0; i < n; i++) {
      if (i in arr) {
        let value = arr[i];
        let include = await fn.call(self, value, i, arr);
        if (include) {
          values[valuesLength++] = value;
        }
      }
    }
    return values;
  }
docs: Calls a function for each element in an array, and if the function returns
  true adds the element to a new array.
  
  If the return value of the filter function is a promise, this function
  will wait for it to be fulfilled before determining whether to insert the
  element into the new array.
  
  If the filter function throws or returns a rejected promise, the promise
  returned by this function will be rejected with the same reason. Only the
  first failure will be reported; all subsequent errors will be silently
  ignored.
  
  @param {!(Array<TYPE>|IThenable<!Array<TYPE>>)} array The array to iterate
  over, or a promise that will resolve to said array.
  @param {function(this: SELF, TYPE, number, !Array<TYPE>): (
  boolean|IThenable<boolean>)} fn The function
  to call for each element in the array.
  @param {SELF=} self The object to be used as the value of 'this' within `fn`.
  @template TYPE, SELF