如何从回调函数中获取(返回)一个数值

huangapple go评论60阅读模式
英文:

How to get (return) a value out of a callback

问题

ipcMain.handle("get-menu-data", () => {
  foo((response) => {
    menuData = response;
    console.log(menuData); // [ { id: 2, title: 'Google' }, { id: 6, title: 'Bing' } ]
  });
  console.log(menuData); // menuData is not defined
  return menuData; //我需要从ipcMain.handle函数中返回这个变量到preload.js。
});
英文:

Good evening! How can I return a value from a callback function in my case? Thanks!


ipcMain.handle("get-menu-data", () => {
  foo((response) => {
    menuData = response;
    console.log(menuData); // [ { id: 2, title: 'Google' }, { id: 6, title: 'Bing' } ]
  });
  console.log(menuData); // menuData is not defined
  return menuData; //I need to return this variable from ipcMain.handle function to preload.js.
});

function foo(callback) {
  db.all("SELECT * FROM projects", (err, res) => {
    if (err) {
      console.log(err);
    } else {
      return callback(res);
    }
  });
}

答案1

得分: 2

问题

您不能从异步回调函数中return。但还有另一个问题,如果发生错误,foo的调用者将无限期等待回调函数的调用。

function foo(callback) {
  db.all("SELECT * FROM projects", (err, res) => {
    if (err) {
      console.log(err); // ❌ callback is never called
    } else {
      return callback(res); // ❌ return does nothing here
    }
  });
}

您是否注意到db.all如何将(err, res)传递给回调函数?这是一种Node风格的错误优先回调

选项 1

foo编写为接受Node风格的错误优先回调 -

function foo(callback) {
  db.all("SELECT * FROM projects", (err, res) => {
    if (err)
      callback(err) // ✅ callback with error
    else
      callback(null, res) // ✅ callback with null error and response
  })

这与编写这个简化形式完全相同 -

function foo(callback) {
  db.all("SELECT * FROM projects", callback)
}

ipcMain.handle接受一个基于Promise的异步处理程序。我们可以像这样将foo封装在Promise中 -

ipcMain.handle("get-menu-data", () => {
  return new Promise((resolve, reject) => {
    foo((err, res) => {
      if (err) reject(err)
      else resolve(res)
    })
  })
}

选项 2

我认为将foo转换为基于Promise的函数会更好 -

function foo() {
  return new Promise((resolve, reject) => {
    db.all("SELECT * FROM projects", (err, res) => {
      if (err) reject(err) // ✅ errors are rejected
      else resolve(res) // ✅ response is resolved
    })
  })
}

现在编写异步处理程序 -

ipcMain.handle("get-menu-data", async () => {
  const menuData = await foo()
  return menuData
})

但是,由于foo已经返回了一个Promise,您可以更轻松地重写此内容 -

ipcMain.handle("get-menu-data", () => {
  return foo()
})

甚至更简单 -

ipcMain.handle("get-menu-data", foo)

选项 3

Node内置了一个名为util.promisify的函数,它将基于回调的函数转换为基于Promise的函数。而不是创建一个foo包装函数,我们可以直接将db.all变为Promise -

import { promisify } from "node:util"

const query = promisify(db.all)

ipcMain.handle("get-menu-data", () => {
  return query("SELECT * FROM projects")
})
英文:

problem

You can't return from an asynchronous callback. But there's another issue, if an error happens, the caller of foo will wait indefinitely for the callback to be called.

function foo(callback) {
  db.all("SELECT * FROM projects", (err, res) => {
    if (err) {
      console.log(err); // ❌ callback is never called
    } else {
      return callback(res); // ❌ return does nothing here
    }
  });
}

Do you notice how db.all passes (err, res) to the callback? This is a node-style error-first callback.

option 1

Write foo to accept a node-style error-first callback -

function foo(callback) {
  db.all("SELECT * FROM projects", (err, res) => {
    if (err)
      callback(err) // ✅ callback with error
    else
      callback(null, res) // ✅ callback with null error and response
  })

Which is exactly the same as writing this simplified form -

function foo(callback) {
  db.all("SELECT * FROM projects", callback)
}

ipcMain.handle accepts an asynchronous promise-based handler. We can wrap foo in a promise like so -

ipcMain.handle("get-menu-data", () => {
  return new Promise((resolve, reject) => {
    foo((err, res) => {
      if (err) reject(err)
      else resolve(res)
    })
  })
})

option 2

I think it would be better to convert foo to a promise-based function -

function foo() {
  return new Promise((resolve, reject) => {
    db.all("SELECT * FROM projects", (err, res) => {
      if (err) reject(err) // ✅ errors are rejected
      else resolve(res) // ✅ response is resolved
    })
  })
}

Now write asynchronous handler -

ipcMain.handle("get-menu-data", async () => {
  const menuData = await foo()
  return menuData
})

However, since foo already returns a Promise, you can rewrite this more easily -

ipcMain.handle("get-menu-data", () => {
  return foo()
})

Even easier -

ipcMain.handle("get-menu-data", foo)

option 3

Node has a built-in function called util.promisify that converts a callback-based function to a promised-based one. Instead of creating a foo wrapper function, we can promisify db.all directly -

import { promisify } from "node:util"

const query = promisify(db.all)

ipcMain.handle("get-menu-data", () => {
  return query("SELECT * FROM projects")
})

huangapple
  • 本文由 发表于 2023年2月9日 02:15:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75390089.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定