docs: def execute_async(self, output_options=None, sampling=None, context=None, query_params=None):
      """ Initiate the query and return a QueryJob.
  
      Args:
        output_options: a QueryOutput object describing how to execute the query
        sampling: sampling function to use. No sampling is done if None. See bigquery.Sampling
        context: an optional Context object providing project_id and credentials. If a specific
            project id or credentials are unspecified, the default ones configured at the global
            level are used.
        query_params: a dictionary containing query parameter types and values, passed to BigQuery.
      Returns:
        A Job object that can wait on creating a table or exporting to a file
        If the output is a table, the Job object additionally has run statistics
        and query results
      Raises:
        Exception if query could not be executed.
      """
  
      # Default behavior is to execute to a table
      if output_options is None:
        output_options = QueryOutput.table()
  
      # First, execute the query into a table, using a temporary one if no name is specified
      batch = output_options.priority == 'low'
      append = output_options.table_mode == 'append'
      overwrite = output_options.table_mode == 'overwrite'
      table_name = output_options.table_name
      context = context or google.datalab.Context.default()
      api = _api.Api(context)
      if table_name is not None:
        table_name = _utils.parse_table_name(table_name, api.project_id)
  
      sql = self._expanded_sql(sampling)
  
      try:
        query_result = api.jobs_insert_query(sql, table_name=table_name,
                                             append=append, overwrite=overwrite, batch=batch,
                                             use_cache=output_options.use_cache,
                                             allow_large_results=output_options.allow_large_results,
                                             table_definitions=self.data_sources,
                                             query_params=query_params)
      except Exception as e:
        raise e
      if 'jobReference' not in query_result:
        raise Exception('Unexpected response from server')
  
      job_id = query_result['jobReference']['jobId']
      if not table_name:
        try:
          destination = query_result['configuration']['query']['destinationTable']
          table_name = (destination['projectId'], destination['datasetId'], destination['tableId'])
        except KeyError:
          # The query was in error
          raise Exception(_utils.format_query_errors(query_result['status']['errors']))
  
      execute_job = _query_job.QueryJob(job_id, table_name, sql, context=context)
  
      # If all we need is to execute the query to a table, we're done
      if output_options.type == 'table':
        return execute_job
      # Otherwise, build an async Job that waits on the query execution then carries out
      # the specific export operation
      else:
        export_args = export_kwargs = None
        if output_options.type == 'file':
          if output_options.file_path.startswith('gs://'):
            export_func = execute_job.result().extract
            export_args = [output_options.file_path]
            export_kwargs = {
              'format': output_options.file_format,
              'csv_delimiter': output_options.csv_delimiter,
              'csv_header': output_options.csv_header,
              'compress': output_options.compress_file
            }
          else:
            export_func = execute_job.result().to_file
            export_args = [output_options.file_path]
            export_kwargs = {
              'format': output_options.file_format,
              'csv_delimiter': output_options.csv_delimiter,
              'csv_header': output_options.csv_header
            }
        elif output_options.type == 'dataframe':
          export_func = execute_job.result().to_dataframe
          export_args = []
          export_kwargs = {
            'start_row': output_options.dataframe_start_row,
            'max_rows': output_options.dataframe_max_rows
          }
  
        # Perform the export operation with the specified parameters
        export_func = google.datalab.utils.async_function(export_func)
        return export_func(*export_args, **export_kwargs)