如何在PowerShell中执行异步Node.js代码并获取返回结果?
解决PowerShell调用Node.js异步脚本无法获取结果的问题
问题背景
在PowerShell中调用Node.js脚本执行异步HubSpot API请求时,PowerShell会在Node脚本的异步操作完成前继续执行,无法捕获异步返回的联系人数据。尝试使用Start-Job也未能解决问题。
现有代码
PowerShell脚本
$hubspot_api_key = 'xxx' $result = $(node hubspot.js $($hubspot_api_key) 'ci') Write-Output 'Results:' $result
Node.js核心代码
(async () => { return await getContacts(); })()
Node.js补充代码(getContacts函数)
getContacts = async () => { const emailFilter = `*bstdev${environment}*` console.log('emailFilter', emailFilter); const filter = { propertyName: 'email', operator: 'EQ', value: emailFilter } const filterGroup = { filters: [filter] } const sort = JSON.stringify({ propertyName: 'createdate', direction: 'DESCENDING' }) const query = 'test' const properties = ['createdate', 'firstname', 'lastname'] const limit = 100 const after = 0 const contacts = []; const publicObjectSearchRequest = { filterGroups: [filterGroup], sorts: [sort], query, properties, limit, after, } let result = await hubspotClient.crm.contacts.searchApi.doSearch(publicObjectSearchRequest); if(result.results){ result.results.forEach((publicObject) => { contacts.push(publicObject.properties); }) while(result.paging){ publicObjectSearchRequest.after = result.paging.next.after; await setAsyncTimeout(async() => { result = await hubspotClient.crm.contacts.searchApi.doSearch(publicObjectSearchRequest); if(result.results){ result.results.forEach((publicObject) => { contacts.push(publicObject.properties); }) } }, 1000); } } console.log('count', contacts.length); return contacts; }
问题根源
- Node.js中的异步立即执行函数(IIFE)仅启动了异步操作,但未等待其完成就退出进程,导致PowerShell无法捕获最终结果。
- Async函数的返回值不会自动输出到标准输出(stdout),PowerShell只能通过捕获stdout内容获取结果。
- 错误使用
Start-Job:$someFunc已经是node命令的执行结果,而非可执行的脚本块,因此无法通过Job机制等待结果。
解决方案
1. 修改Node.js脚本,确保异步操作完成后输出结果
- 等待异步函数执行完成,将结果以JSON格式输出到stdout(方便PowerShell解析)。
- 补全缺失的依赖代码(如
setAsyncTimeout定义、hubspotClient初始化、环境变量获取)。 - 处理错误,避免进程意外退出。
修改后的hubspot.js代码:
// 补全setAsyncTimeout函数定义 function setAsyncTimeout(callback, delay) { return new Promise(resolve => { setTimeout(async () => { await callback(); resolve(); }, delay); }); } // 从命令行参数获取API密钥和环境 const hubspotApiKey = process.argv[2]; const environment = process.argv[3]; // 初始化HubSpot客户端(需确保已安装@hubspot/api-client包) const { Client } = require('@hubspot/api-client'); const hubspotClient = new Client({ accessToken: hubspotApiKey }); async function getContacts() { const emailFilter = `*bstdev${environment}*`; console.log('emailFilter', emailFilter); const filter = { propertyName: 'email', operator: 'EQ', value: emailFilter }; const filterGroup = { filters: [filter] }; const sort = { propertyName: 'createdate', direction: 'DESCENDING' }; // 无需JSON.stringify,直接传对象 const query = 'test'; const properties = ['createdate', 'firstname', 'lastname']; const limit = 100; const after = 0; const contacts = []; const publicObjectSearchRequest = { filterGroups: [filterGroup], sorts: [sort], query, properties, limit, after, }; try { let result = await hubspotClient.crm.contacts.searchApi.doSearch(publicObjectSearchRequest); if (result.results) { result.results.forEach((publicObject) => { contacts.push(publicObject.properties); }); while (result.paging) { publicObjectSearchRequest.after = result.paging.next.after; await setAsyncTimeout(async () => { result = await hubspotClient.crm.contacts.searchApi.doSearch(publicObjectSearchRequest); if (result.results) { result.results.forEach((publicObject) => { contacts.push(publicObject.properties); }); } }, 1000); } } console.log('count', contacts.length); // 将结果以JSON格式输出到stdout,供PowerShell捕获 console.log(JSON.stringify(contacts)); } catch (error) { // 输出错误信息到stderr,避免干扰结果捕获 console.error('Error fetching contacts:', error); process.exit(1); } } // 等待异步函数执行完成 getContacts();
2. 修改PowerShell脚本,直接同步调用并解析结果
无需使用Start-Job,只要Node脚本等待异步操作完成后输出结果,PowerShell会自动等待node命令执行完毕再继续。可以将捕获的JSON字符串转换为PowerShell对象,方便后续处理。
修改后的PowerShell脚本:
$hubspot_api_key = 'xxx' # 调用Node脚本,捕获stdout输出 $rawResult = $(node hubspot.js $hubspot_api_key 'ci') # 提取JSON结果(过滤掉日志信息,只取最后一行的JSON) $jsonResult = $rawResult | Where-Object { $_ -match '^\[.*\]$' } | Select-Object -Last 1 # 转换为PowerShell对象 $result = if ($jsonResult) { ConvertFrom-Json $jsonResult } else { @() } Write-Output 'Results:' $result
关键说明
- Node脚本中必须用
console.log(JSON.stringify(contacts))将结果输出到stdout,PowerShell才能捕获到结构化数据。 - 过滤日志信息(如
emailFilter、count)是为了避免干扰JSON解析,确保只处理结果数据。 - 若Node脚本执行出错,错误信息会输出到stderr,PowerShell不会捕获到,可通过
$LASTEXITCODE检查Node进程的退出码判断是否执行成功。
内容的提问来源于stack exchange,提问作者Brian Rice
相关产品推荐
相关产品推荐

