英文:
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")
})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论