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

Promise.race触发拒绝时取消其他Promise的执行方案

问题描述

我正在开发一款异步Node.js应用,部分逻辑用Promise.race实现超时控制,但遇到一个问题:processSource(ast)可能会无限运行,当前的超时逻辑只是停止等待,无法真正终止该函数的执行,想知道有没有可行的实现方案。

当前代码

async function callDeobfuscator(ast) {
  const withTimeout = (promise) => {
    let timeoutPid;
    const timeoutPromise = new Promise((resolve, reject) => 
      timeoutPid = setTimeout(reject, timeout));
    return Promise.race([
        promise,
        timeoutPromise
    ]).finally(() => {
        if (timeoutPid) {
          clearTimeout(timeoutPid);
        }
    });
  };
  return withTimeout(processSource(ast));
};
可行解决方案

首先明确:Promise.race仅能终止对异步任务的等待,无法主动终止未完成的异步/同步执行逻辑。针对不同类型的processSource实现,有以下几种可行方案:

方案1:使用AbortController(适配支持中断的异步操作)

如果processSource内部调用了支持AbortSignal的API(如Node.js文件流、fetch、部分第三方库),可以通过AbortController传递中断信号,主动终止执行:

async function callDeobfuscator(ast) {
  const controller = new AbortController();
  const timeoutPid = setTimeout(() => controller.abort(), timeout);

  try {
    // 假设processSource可接收AbortSignal参数
    return await processSource(ast, { signal: controller.signal });
  } finally {
    clearTimeout(timeoutPid);
  }
};

需要同步修改processSource,在关键逻辑节点检查中断状态,或把信号传递给内部支持中断的操作:

async function processSource(ast, { signal }) {
  // 同步逻辑中定期检查中断
  if (signal.aborted) throw new Error('操作已中断');
  
  // 异步操作传递信号
  await someAsyncTask(ast, { signal });
}

方案2:子进程隔离(适配CPU密集/无法中断的同步逻辑)

如果processSource是CPU密集型的同步代码(比如无限循环),单线程Node.js无法中断正在执行的同步函数,必须通过子进程隔离实现强制终止:

主进程代码

const { fork } = require('child_process');
const path = require('path');

async function callDeobfuscator(ast) {
  return new Promise((resolve, reject) => {
    const worker = fork(path.join(__dirname, 'deobfuscator-worker.js'));
    const timeoutPid = setTimeout(() => {
      worker.kill(); // 超时后强制杀死子进程
      reject(new Error('处理超时'));
    }, timeout);

    worker.send(ast);

    worker.on('message', (result) => {
      clearTimeout(timeoutPid);
      worker.kill();
      resolve(result);
    });

    worker.on('error', (err) => {
      clearTimeout(timeoutPid);
      reject(err);
    });

    worker.on('exit', (code) => {
      if (code !== 0 && timeoutPid) {
        reject(new Error(`子进程异常退出,代码:${code}`));
      }
    });
  });
};

子进程文件deobfuscator-worker.js

process.on('message', async (ast) => {
  try {
    const result = await processSource(ast);
    process.send(result);
    process.exit(0);
  } catch (err) {
    process.send({ error: err.message });
    process.exit(1);
  }
});

// 原processSource逻辑
async function processSource(ast) {
  // 你的业务代码
}

该方案通过进程隔离实现彻底终止,代价是进程间通信的少量性能开销。

方案3:Worker线程隔离(轻量级替代子进程)

如果不想用完整的子进程,可以用Node.js的worker_threads模块,实现轻量级线程隔离,终止逻辑和子进程类似:

主进程代码

const { Worker } = require('worker_threads');
const path = require('path');

async function callDeobfuscator(ast) {
  return new Promise((resolve, reject) => {
    const worker = new Worker(path.join(__dirname, 'deobfuscator-worker.js'), {
      workerData: ast
    });
    const timeoutPid = setTimeout(() => {
      worker.terminate(); // 终止Worker线程
      reject(new Error('处理超时'));
    }, timeout);

    worker.on('message', (result) => {
      clearTimeout(timeoutPid);
      worker.terminate();
      resolve(result);
    });

    worker.on('error', (err) => {
      clearTimeout(timeoutPid);
      reject(err);
    });

    worker.on('exit', (code) => {
      if (code !== 0 && timeoutPid) {
        reject(new Error(`Worker线程异常退出,代码:${code}`));
      }
    });
  });
};

Worker线程文件deobfuscator-worker.js

const { parentPort, workerData } = require('worker_threads');

async function run() {
  try {
    const result = await processSource(workerData);
    parentPort.postMessage(result);
  } catch (err) {
    parentPort.postMessage({ error: err.message });
  }
}

run();

async function processSource(ast) {
  // 你的业务代码
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 01:10:18