Node.js 从函数返回一个承诺
Posted
技术标签:
【中文标题】Node.js 从函数返回一个承诺【英文标题】:Node.js returning a promise from a function 【发布时间】:2018-09-14 06:50:15 【问题描述】:我正在探索 node.js 中承诺和回调的可能性 我正在尝试找到一种使此代码起作用的方法。目前我面临的问题是,当我调用一个函数并想要使用返回值时,它还没有准备好。我知道我必须做什么,但不知道怎么做。基本上,我必须让 insertAddress() 返回一个承诺(这样我就可以在上面使用 .then() ),或者将回调作为参数。为此,我还认为 databaseWork() 应该返回一个承诺。但我不知道在哪里添加它。 问题位于“console.log(out)”中,它在设置 out 变量之前运行(因为 insertAddress 仍在运行)。 这是我的代码
app.js
-----
const databaseWork = require('./db/mysql.js').databaseWork;
app.use('/test', (req, resp) =>
var address =
country : "Country",
city : "Randomcity",
street : "Random",
number : 6,
postalcode : "A789",
province : "a province"
var out = insertAddress(address); //<== takes time to finish, is not ready when the next console.log finishes
console.log(out);
);
function insertAddress(address)
var rows
databaseWork(
//Following anonymous function contains the actual workload. That has to be done inside a transaction
async (connection) =>
rows = await insertAddressQuery(address,connection);
console.log(rows); //this one waits for insertAddressQuery to be complete
)
return rows; //this will run before insertAddressQuery is complete
function insertAddressQuery(address,connection)
return new Promise( (resolve, reject) =>
//async job
connection.query('INSERT INTO address (country,city,Street,number,postalcode,province) VALUES(?,?,?,?,?,?)', [address.country,'4','5',6,'7','8'] , (err, rows) =>
if (err) reject(err);
resolve(rows);
);
);
;
/db/mysql.js
------------
var mysql = require('mysql');
var dbpool = mysql.createPool(
host: process.env.HOST_DB,
user: process.env.USER_DB,
password: process.env.PWD_DB,
database: process.env.DB
);
function databaseWork(workload)
dbpool.getConnection( async (err, connection) =>
await beginTransaction(connection);
await workload(connection);
await commitTransaction(connection)
connection.release();
);
function beginTransaction(connection)
return new Promise( (resolve, reject) =>
//async job
connection.beginTransaction( (err) =>
if (err) reject(err);
resolve();
);
);
;
function commitTransaction(connection)
return new Promise( (resolve, reject) =>
//async job
connection.commit( (err) =>
if (err) reject(err);
resolve();
);
);
;
exports.databaseWork = databaseWork;
【问题讨论】:
【参考方案1】:一种方法是使用异步等待。
var example = async (req, res) =>
var response = await myAsyncTask();
// this will get logged once the async task finished running.
console.log(response)
// Use async await to get response
var myAsyncTask = async () =>
try
var response = await asyncTaskINeedDataFrom()
return response;
catch(err)
return console.log(err);
这里是 npm 模块:https://www.npmjs.com/package/async
【讨论】:
【参考方案2】:你可以在你的databaseWork
:
function databaseWork(workload)
return new Promise((resolve, reject) =>
dbpool.getConnection(async (err, connection) =>
try
await beginTransaction(connection);
var result = await workload(connection);
await commitTransaction(connection)
resolve(result);
catch( err )
reject(err)
finally
connection.release();
);
)
databaseWork
返回的Promise
将由workload
的结果解析。现在您可以将insertAddress
更改为:
async function insertAddress(address)
return databaseWork(connection =>
return insertAddressQuery(address,connection);
)
然后您需要将路线更改为:
app.use('/test', async (req, resp) =>
var address =
country: "Country",
city: "Randomcity",
street: "Random",
number: 6,
postalcode: "A789",
province: "a province"
var out = await insertAddress(address); // use await here to wait for insertAddress to be finished
console.log(out);
);
*UPDATE 代码,带有返回 Promise 的 getConnection
函数:
function getConnection()
return new Promise((resolve, reject) =>
dbpool.getConnection((err, connection) =>
if (err)
reject(err)
else
resolve(connection);
)
);
async function databaseWork(workload)
var connection = await getConnection();
var result;
try
await beginTransaction(connection)
result = await workload(connection)
await commitTransaction(connection)
catch (err)
// a rollback might be neccesaary at that place
throw err
finally
connection.release();
return result;
【讨论】:
@Bosiwow 但请注意错误处理。这个解决方案仍然需要一些工作,因为我没有修复我们代码中的其他缺陷。你不检查getConnection
是否有错误。此外,如果workload
失败,您可能需要在 catch 块中添加rollback
。这段代码只是为了给你一个如何解决它的一般想法。您甚至可以考虑创建 getConnection
的异步版本,以使您的 databaseWork
更清晰。
我不能把'dbpool.getConnection(async (err, connection) => '放在try块里面吗?我可以在catch块里面做回滚吗?如果里面回滚失败怎么办? catch 块。这不好,对吧?finally 块中的释放怎么办。如果失败了怎么办?
@Bosiwow 不,你不能将它放在 try catch 块中 dbpool.getConnection
不会因抛出异常而失败,但会将错误传递给回调。我用返回承诺的getConnection
更新了问题。如果getConnection
被拒绝,databaseWork
将不会被拒绝。对于您的其余问题。这超出了您原始问题的范围。如果您在 SO 上没有找到关于该问题的答案,那么您可能会提出一个新问题。
您好,非常感谢您的回复。您说“如果 getConnection 被拒绝,则不会拒绝 databaseWork。”。如果我在 getConnection() 被拒绝时理解正确。不会有连接对象。因此“await beginTransaction(connection)”也将被拒绝。但这不会触发捕获,不是吗?编辑:好的,当一个承诺被拒绝时,cath 被称为developer.mozilla.org/en-US/docs/Web/javascript/Reference/…
@Bosiwow 抱歉,打错了。现在使用await
,如果getConnection
,databaseWork
将被拒绝,现在您可以将await getConnection
放在try
块中,或者您让databaseWork
失败并出现getConnection
的错误。 以上是关于Node.js 从函数返回一个承诺的主要内容,如果未能解决你的问题,请参考以下文章
Node.js / Javascript 多重递归承诺在视图中返回