【问题标题】:How can I await data from a callback function and then return it?如何等待来自回调函数的数据然后返回它?
【发布时间】:2020-06-22 02:52:29
【问题描述】:

我在一个异步函数中,试图从回调函数中返回数据:

async function getData(){
    const client = new google.auth.JWT(
        keys.client_email,
        null,
        keys.private_key,
        ['https://www.googleapis.com/auth/spreadsheets']    
    )

    let returnData
    const finalData = (data) => {
        returnData = data
    }

    async function gsrun(client) {
        const gsapi = google.sheets({version:'v4', auth: client})

        const options = {
            spreadsheetId: '1d3ZiP1I9jJ2ddlD1Hx2ylWn1VFD_5lYQ9Ps9e9gEqI',
            range: 'Sheet1!A1:H5'
        }

        const data = await gsapi.spreadsheets.values.get(options)

        return data.data.values
    }

    client.authorize( async (err, tokens)=> {
        if(err) return console.log(err)
        let data = await gsrun(client)
        finalData(data)
    })

    return returnData
}

在控制台中我得到:Promise { undefined }。我应该如何等待该承诺解决或等待数据?

【问题讨论】:

标签: node.js


【解决方案1】:

您的 client.authorize 已经在等待 gsrun() 函数返回解析(我不确定如何处理来自 gsrun() 的拒绝,但我建议您使用 .then() 来处理解析/拒绝(如果未实现) try,catch 语句)。

另一个问题是,尽管您在等待 gsrun(client),但以下代码仍会运行

return returnData

因为它不在 finalData() 函数中。我建议你只执行它设置。

这里是为了说明returnData是在数据赋值给它之前返回的

function returnPromise() {
    return new Promise((resolve, reject) => {
      setTimeout(()=>{
        resolve('Success')
      },2000)
      // reject('err')
    })
}

async function test(){
  returnPromise().then(
    resolve=>{console.log(resolve)},
    reject=>{console.log(reject)}
  )
}

test()
console.log('I COME HERE FIRST') // Executed first before promise is returned

这里有一个简单的例子来说明如何实现拒绝处理(仅供参考)

function gsrun() {
    return new Promise((resolve, reject) => {
      //resolve('Success')
       reject('err')
    })
}

async function authorizeCallback(){
    gsrun().then(
    resolve=>{finalData(resolve)},
    reject=>{console.log(reject)} // do error handling
  )
}

【讨论】:

  • 我知道函数执行的顺序,但我不知道如何解决这个问题。我应该等待什么或应该改变什么?
  • 认为 Felix King 在明确界定问题范围方面做得更好。尽管如此,通过重新定位您的“return returnData;”来回答您的问题。进入 finalData() 函数实际上解决了这个问题。这样一旦你的 gsrun() 返回了 Promise,finalData() 就会被执行。哦,我没有意识到你编辑了你的帖子以获得完整的代码。很抱歉发布参考之前代码的答案。
  • 感谢您的解释,非常感谢!
【解决方案2】:

在分配数据之前,您仍在尝试返回。在client.authorize 调用回调之前,您不会“等待”,因为您不能。如果同步调用回调,则只能“从回调中返回数据”。但这里不是这样。将回调声明为async 并不重要,重要的是调用者(即client.authorize)如何/何时调用回调。

client.authorize 包装在一个promise 中,将await 包装在你的getData 函数中。

async function gsrun(client) {
  const gsapi = google.sheets({
    version: 'v4',
    auth: client
  })

  const options = {
    spreadsheetId: '1d3ZiP1I9jJ2ddlD1Hx2ylWn1VFD_5lYQ9Ps9e9gEqI',
    range: 'Sheet1!A1:H5'
  }

  const data = await gsapi.spreadsheets.values.get(options)

  return data.data.values
}


function authorize(client) {
  return new Promise((resolve, reject) => {
    client.authorize((err, tokens) => {
      if (err) {
        reject(err);
      } else {
        resolve(tokens);
      }
    });
  });
}


async function getData() {
  const client = new google.auth.JWT(
    keys.client_email,
    null,
    keys.private_key, ['https://www.googleapis.com/auth/spreadsheets']
  )

  await authorize(client);
  return await gsrun(client);
}

这里authorize会在认证失败时抛出错误,如果成功则返回令牌。


I wrote a post about callbacks and data。虽然它不涉及承诺,但也许它可以帮助您理解回调。

【讨论】:

    猜你喜欢
    • 2018-11-04
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 2021-11-13
    • 2019-07-25
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多