static wrapChainCallback_(callback, value, newPromise) {
    try {
      const ret = callback(value);

      if (ret && ret.promise && ret.abort) {
        // This is an abortable operation, with its own abort() method.
        // After this point, abort() should abort the operation from the
        // callback, and the new promise should be tied to the promise
        // from the callback's operation.
        newPromise.resolve(ret.promise);
        // This used to say "return ret.abort;", but it caused subtle issues by
        // unbinding part of the abort chain.  There is now a test to ensure
        // that we don't call abort with the wrong "this".
        return () => ret.abort();
      } else {
        // This is a Promise or a plain value, and this step cannot be aborted.
        newPromise.resolve(ret);
        // Abort is complete when the returned value/Promise is resolved or
        // fails, but never fails itself nor returns a value.
        return () => Promise.resolve(ret).then(() => {}, () => {});
      }
    } catch (exception) {
      // The callback threw an exception or error.  Reject the new Promise and
      // resolve any future abort call right away.
      newPromise.reject(exception);
      return () => Promise.resolve();
    }
  }
@param {(function(T):U|
         function(T):!Promise<U>|
         function(T):!shaka.util.AbortableOperation.<U>|
         function(*))} callback
  A callback to be invoked with the given value.
@param {T} value
@param {!shaka.util.PublicPromise} newPromise The promise for the next
  stage in the chain.
@return {function():!Promise} The next abort() function for the chain.
@private
@template T, U