AWS Serverless Node.js环境下Promise.race()返回缓存结果问题
问题根因
你遇到的现象和Promise.race本身无关,也不是Serverless平台特意缓存了Promise结果,核心原因是AWS Lambda执行环境复用机制和代码中变量的作用域设置错误导致的:
你将promiseTimeout和mainPromise两个Promise实例定义在了Handler函数的全局作用域中,而AWS Lambda冷启动完成后,后续的请求会复用同一个执行环境(热启动),全局作用域的代码仅会在冷启动时执行一次。也就是说第一次调用触发了两个定时器之后,后续所有复用该执行环境的调用,拿到的都是已经执行完成、处于已解决状态的Promise实例,此时Promise.race会直接返回数组中第一个已解决的Promise的结果,这也就是你调整数组顺序后返回值会跟着变化的原因。
问题解答
该场景下函数是否会缓存Promise的返回结果?
不是函数特意缓存了Promise结果,是Serverless执行环境的复用特性导致全局作用域的Promise实例被复用,它们的执行结果在首次冷启动调用后就已经确定,后续调用直接读取了已完成的Promise结果。Serverless运行环境是否支持Promise.race()方法?
完全支持。你使用的runtime是Node.js 14.x,原生完整支持ES6标准的Promise.race方法,该能力和Serverless运行环境无关,问题完全出自代码的作用域设置错误。
修复方案
将两个Promise实例的定义移动到Handler函数内部,保证每次调用函数时都会创建新的Promise实例、重新触发定时器即可:
export const triggerVerifySls = async (event: any, context: any) => { context.callbackWaitsForEmptyEventLoop = false; // 将Promise定义移到Handler内部,每次调用都会重新初始化 const promiseTimeout = new Promise((resolve, _) => { setTimeout(() => { resolve('promise Timeout'); }, 20000); }); const mainPromise = new Promise((resolve, _) => { setTimeout(() => { resolve('Main promise finished'); }, 21000); }); const triggerStatus = await Promise.race([mainPromise, promiseTimeout]); const response = { statusCode: 200, body: JSON.stringify(triggerStatus), }; return response; };
内容的提问来源于stack exchange,提问作者Pablo Alessandro Santos Hugen

