如何在循环中多次调用异步函数PageSpeedCall?
如何在循环中多次调用异步的PageSpeedCall方法
嘿,我来帮你搞定这个异步循环调用的问题~首先得先调整一下你的原函数,因为它现在硬编码了websites[0],没法动态传入不同的网站地址,然后再根据你的需求选择串行或并行的调用方式,毕竟异步操作在循环里很容易出现顺序混乱或者并发超限的问题。
第一步:改造原函数,支持动态传参并完善错误处理
你的原函数是回调风格的,而且缺少错误处理逻辑,我们先把它改成能接收目标网站参数,同时补上错误处理:
// 改造后的回调版函数,支持传入要检测的网站 function PageSpeedCall(site, callback) { const pagespeedCall = `https://www.googleapis.com/pagespeedonline/v4/runPagespeed?url=https://${site}&strategy=mobile&key=${keys.pageSpeed}`; let results = ''; https.get(pagespeedCall, resource => { resource.setEncoding('utf8'); resource.on('data', data => { results += data; }); resource.on('end', () => { callback(null, results); }); // 处理响应流的错误 resource.on('error', err => { callback(err); }); }) // 处理get请求本身的错误 .on('error', err => { callback(err); }); }
如果更习惯现代JS的Promise/async-await写法,也可以把它封装成Promise版本,后续处理循环会更顺手:
// 封装成Promise版本的函数 function pageSpeedCall(site) { return new Promise((resolve, reject) => { const pagespeedCall = `https://www.googleapis.com/pagespeedonline/v4/runPagespeed?url=https://${site}&strategy=mobile&key=${keys.pageSpeed}`; let results = ''; https.get(pagespeedCall, resource => { resource.setEncoding('utf8'); resource.on('data', data => { results += data; }); resource.on('end', () => { resolve(results); }); resource.on('error', err => { reject(err); }); }) .on('error', err => { reject(err); }); }); }
第二步:循环调用的两种方案
方案1:串行调用(逐个执行,适合API有频率限制的情况)
如果你的网站数量较多,或者PageSpeed API的配额有限,建议用串行方式,避免触发限流错误。
用async-await + for...of(推荐)
async function runSerialChecks() { // 假设websites是你的目标网站数组,比如:const websites = ["example.com", "test.com", ...]; for (const site of websites) { try { const result = await pageSpeedCall(site); // 解析结果并处理,比如存到数组或打印 const parsedResult = JSON.parse(result); console.log(`✅ 完成 ${site} 的检测:`, parsedResult); // 如果需要避免触发API限流,可以加个延迟 // await new Promise(resolve => setTimeout(resolve, 1000)); } catch (err) { console.error(`❌ 检测 ${site} 失败:`, err); } } } // 启动检测 runSerialChecks();
用传统回调+递归(适合不想用Promise的场景)
function runSerialWithCallbacks(index = 0) { if (index >= websites.length) { console.log("🎉 所有网站检测完成!"); return; } const currentSite = websites[index]; PageSpeedCall(currentSite, (err, result) => { if (err) { console.error(`❌ ${currentSite} 检测失败:`, err); } else { const parsedResult = JSON.parse(result); console.log(`✅ ${currentSite} 检测结果:`, parsedResult); } // 递归调用,处理下一个网站 runSerialWithCallbacks(index + 1); }); } // 启动检测 runSerialWithCallbacks();
方案2:并行调用(同时发起所有请求,速度更快)
如果网站数量不多,且API允许并发请求,可以用并行方式,效率更高:
async function runParallelChecks() { // 为每个网站创建一个检测Promise const checkPromises = websites.map(site => { return pageSpeedCall(site) .then(result => ({ site, data: JSON.parse(result) })) .catch(err => ({ site, error: err })); }); // 等待所有请求完成 const allResults = await Promise.all(checkPromises); // 遍历处理所有结果 allResults.forEach(item => { if (item.error) { console.error(`❌ ${item.site} 检测失败:`, item.error); } else { console.log(`✅ ${item.site} 检测结果:`, item.data); } }); } // 启动检测 runParallelChecks();
重要提醒
- API限流问题:PageSpeed API有请求配额限制,并行调用过多可能会返回429错误,这种情况下优先选择串行并添加适当延迟
- 错误处理:一定要保留错误处理逻辑,避免某个网站检测失败导致整个流程卡住
- 参数校验:可以在函数里加个简单的参数校验,确保传入的site是有效的域名
内容的提问来源于stack exchange,提问作者Alex Ironside
相关产品推荐
相关产品推荐

