You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Google表格Apps Script中实现带Promise的简易线程池

实现Google Apps Script原生简易线程池(带Promise支持)

首先得明确:Google Apps Script本身没有真正的多线程环境,但我们可以通过并发请求控制+Promise队列来模拟线程池的效果,实现你需要的「同时处理N个任务、获取返回值、等待全部完成」的需求。下面是一个完全基于原生JS的非压缩版实现,完美适配你的场景。

核心线程池实现

这个线程池类会维护一个任务队列,控制同时运行的任务数量,每个任务都是返回Promise的异步函数,完成后自动取下一个任务执行,最后可以获取所有任务的结果:

class ThreadPool {
  constructor(maxConcurrency = 5) {
    this.maxConcurrency = maxConcurrency;
    this.runningTasks = 0;
    this.taskQueue = [];
    this.results = [];
    this.resolveAll = null;
    // 初始化一个Promise,用于等待所有任务完成
    this.allCompleted = new Promise(resolve => {
      this.resolveAll = resolve;
    });
  }

  // 提交任务:传入一个返回Promise的函数
  submit(taskFn) {
    return new Promise((resolve, reject) => {
      this.taskQueue.push({ taskFn, resolve, reject });
      this._processQueue();
    });
  }

  // 处理任务队列
  _processQueue() {
    // 如果还有空闲线程且队列有任务,就启动新任务
    while (this.runningTasks < this.maxConcurrency && this.taskQueue.length > 0) {
      const { taskFn, resolve, reject } = this.taskQueue.shift();
      this.runningTasks++;

      // 执行任务,处理结果
      taskFn()
        .then(result => {
          this.results.push(result);
          resolve(result);
        })
        .catch(error => {
          reject(error);
        })
        .finally(() => {
          this.runningTasks--;
          this._processQueue(); // 任务完成后,继续处理下一个
          // 检查是否所有任务都完成了
          if (this.runningTasks === 0 && this.taskQueue.length === 0) {
            this.resolveAll(this.results);
          }
        });
    }
  }

  // 等待所有任务完成,返回所有结果
  waitForAll() {
    return this.allCompleted;
  }
}

结合你的Google表格场景使用

接下来把你原来的逐行处理逻辑改成用这个线程池,包括处理多步依赖请求的情况:

function processSheetData() {
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = spreadsheet.getActiveSheet();
  const range = sheet.getDataRange();
  const rows = range.getValues();
  // 跳过表头(如果第一行是表头的话)
  const dataRows = rows.slice(1);

  // 创建线程池,设置并发数为5
  const pool = new ThreadPool(5);

  // 遍历每一行,提交任务到线程池
  dataRows.forEach((row, index) => {
    pool.submit(() => processSingleRow(row, index));
  });

  // 等待所有任务完成,然后汇总结果
  pool.waitForAll().then(allResults => {
    // 这里处理所有任务的结果,比如写回表格
    allResults.forEach((result, index) => {
      // 假设结果要写到第index+2行的某一列(因为跳过了表头)
      sheet.getRange(index + 2, 6).setValue(result);
    });
    SpreadsheetApp.getUi().alert('所有数据处理完成!');
  }).catch(error => {
    console.error('处理出错:', error);
    SpreadsheetApp.getUi().alert(`处理失败:${error.message}`);
  });
}

// 处理单行数据的函数(包含多步依赖请求)
function processSingleRow(row, rowIndex) {
  return new Promise((resolve, reject) => {
    try {
      // 第一步:构建payload并发送第一个请求
      const payload1 = {
        // 从row中提取数据,比如row[0], row[1]等
        id: row[0],
        name: row[1]
      };
      const options1 = { method: "POST", payload: payload1 };
      UrlFetchApp.fetch("http://your-first-api-url", options1)
        .then(response1 => {
          const data1 = JSON.parse(response1.getContentText());
          // 第二步:依赖第一个请求的结果,发送第二个请求
          const payload2 = {
            parentId: data1.id,
            detail: row[2]
          };
          const options2 = { method: "POST", payload: payload2 };
          return UrlFetchApp.fetch("http://your-second-api-url", options2);
        })
        .then(response2 => {
          const data2 = JSON.parse(response2.getContentText());
          // 继续后续的3-4个依赖请求...
          // ...省略中间步骤...
          // 最后返回该行的处理结果
          resolve(`行${rowIndex+2}处理完成:${data2.result}`);
        })
        .catch(error => {
          reject(new Error(`行${rowIndex+2}处理失败:${error.message}`));
        });
    } catch (error) {
      reject(new Error(`行${rowIndex+2}初始化失败:${error.message}`));
    }
  });
}

关键说明

  • 并发控制:线程池通过maxConcurrency限制同时运行的任务数,避免一次性发送过多请求导致被API限流,或者触发Apps Script的请求配额限制。
  • 任务结果追踪:每个submit调用返回的Promise可以单独获取该行的结果,waitForAll()则会等待所有任务完成后返回所有结果的数组。
  • 错误处理:单个任务失败不会影响其他任务,你可以在waitForAll()的catch里统一处理全局错误,也可以在单个任务的Promise里做针对性错误处理。
  • 适配Apps Script特性:这里用的是原生Promise和UrlFetchApp,完全符合Apps Script的运行环境,不需要任何外部库。

内容的提问来源于stack exchange,提问作者Deviling Master

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:52:17