如何将Google OAuth授权回调包装为Promise并返回API调用结果
问题分析
你遇到的核心问题是异步回调的特性导致返回值无法传递到外部:script.scripts.run是异步执行的,当你在回调函数里return resp.response.result时,这个return只是回调函数的返回值,而不是testAuth方法的返回值。外部调用goo.test_auth()时,方法会直接执行完毕并返回undefined,此时异步的API请求还没完成,自然拿不到结果。
解决方案:用Promise包装异步操作 + async/await处理异步流程
我们可以把异步的API调用包装成Promise,再通过async/await让异步代码的执行逻辑更接近同步代码,这样就能正确把结果返回给外部了。以下是具体的代码调整步骤:
1. 改造testAuth方法,用Promise包装API调用
把原来的回调式调用改成Promise风格,成功时resolve结果,失败时reject错误:
Goo.prototype.testAuth = function(auth) { return new Promise((resolve, reject) => { const script = google.script('v1'); const cmd = { auth, resource: { function: 'test_auth', devMode: true }, scriptId: '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' }; script.scripts.run(cmd, function(err, resp) { if (err) { const apiError = new Error('The API returned an error: ' + err); console.log(apiError.message); reject(apiError); return; } if (resp.error) { const scriptError = new Error('Script error message: ' + resp.error.details[0].error.errorMessage); console.log(scriptError.message); reject(scriptError); return; } console.log('resp from api call', resp.response.result); resolve(resp.response.result); // 将结果传递给Promise的调用者 }); }); };
2. 改造authorize方法,同样返回Promise
假设你的authorize方法是用来获取授权对象的,也要把它改成Promise风格(否则无法和后续的await配合):
Goo.prototype.authorize = function() { return new Promise((resolve, reject) => { // 这里替换成你原来的授权逻辑,比如读取密钥、获取OAuth token等 // 示例:假设原来的授权是回调式的 google.auth.getClient({ // 你的授权配置,比如keyFile、scopes等 }, (err, auth) => { if (err) { reject(new Error('Authorization failed: ' + err)); return; } resolve(auth); }); }); };
3. 改造test_auth方法为async函数
用async/await串联授权和API调用的异步流程,最终返回结果:
Goo.prototype.test_auth = async function() { try { const auth = await this.authorize(); // 等待授权完成,拿到auth对象 const result = await this.testAuth(auth); // 等待API调用完成,拿到结果 return result; // 结果会被包装成Promise返回给外部 } catch (err) { console.error('Error in test_auth:', err); throw err; // 将错误抛出,让外部调用者处理 } };
4. 外部调用时处理异步结果
因为test_auth现在返回的是Promise,外部需要用await(在async函数内)或者.then()来获取结果:
const Goo = require('./Goo.js'); const goo = new Goo(); // 方式1:用async/await(推荐,代码更简洁) async function main() { try { const response = await goo.test_auth(); console.log('response to use elsewhere ', response); // 在这里可以正常使用response做后续操作 } catch (err) { console.error('Failed to get API response:', err); } } main(); // 方式2:用.then()/.catch()(兼容老代码风格) goo.test_auth() .then(response => { console.log('response to use elsewhere ', response); }) .catch(err => { console.error('Failed to get API response:', err); });
额外优化:利用googleapis的Promise支持
你使用的googleapis@24.0.0版本已经支持Promise化调用——当你调用API方法时不传入回调函数,它会直接返回一个Promise。基于这个特性,testAuth可以简化成更简洁的async函数:
Goo.prototype.testAuth = async function(auth) { const script = google.script('v1'); const cmd = { auth, resource: { function: 'test_auth', devMode: true }, scriptId: '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' }; try { const resp = await script.scripts.run(cmd); if (resp.error) { const scriptError = new Error('Script error message: ' + resp.error.details[0].error.errorMessage); console.log(scriptError.message); throw scriptError; } console.log('resp from api call', resp.response.result); return resp.response.result; } catch (err) { console.log('The API returned an error: ' + err); throw err; } };
这样代码会更清爽,也省去了手动包装Promise的步骤。
内容的提问来源于stack exchange,提问作者Rob Foree
相关产品推荐
相关产品推荐

