首先,如果这个问题已经有答案了,我很抱歉,但是我已经搜索了这种问题,没有找到有用的东西。
我正在开发一个使用mysql npm包查询数据库的NodeJS应用程序。我已经写了几个查询,借助于promise的帮助(因为SQL模块是这样工作的),这些查询都很好。当正常调用查询过程函数get_works
(下面定义)时,我没有问题。
然而,当我在Express路由器中调用这个过程函数时,会出现奇怪的行为。
view.get("/works", (req, res) => { (async () => { res.json(await get_works()); })() }); async function get_works(offset=0,limit=6){ let cdc_database = mysql.createConnection({ /*Filled with credentials*/ }); const get_texts = `SELECT TEXID,TXNOM,TXRES FROM TEXTE LIMIT ${limit} OFFSET ${offset};`; // Valid request /*Two steps: get texts and get authors of each texts*/ cdc_database.connect(); const texts = await database_promise_query(cdc_database, get_texts); /*This await always have a correct output*/ let text_authors = []; for(i = 0; i < texts.length; i++){ get_text_authors = `SELECT AUPRE, AUNOM FROM AUTEURS,ECRIT_PAR\ WHERE AUTEURS.AUTID=ECRIT_PAR.AUTID AND TEXID=${texts[i].TEXID};`; // Request is valid text_authors[i] = (await database_promise_query(cdc_database, get_text_authors)); /* ^^^^^^^^ The await above returns an undefined value randomly when called through the router */ if(text_authors[i] === undefined){ console.error(`[get_works] - Server error on ${i}th text's authors`) text_authors[i] = [{AUPRE: "Prénom", AUNOM: "Nom"}] } } cdc_database.end(); return works_to_JSON(texts, text_authors) }
有时,对数据库的查询将没有未定义的值,但一旦有一个未定义的值,后面的所有值也都是未定义的。
Example trace log (1st call, 3 errors) [ [ RowDataPacket { AUPRE: 'xxx', AUNOM: 'xxx' } ], [ RowDataPacket { AUPRE: 'xxx', AUNOM: "xxx" } ], [ RowDataPacket { AUPRE: 'xxx', AUNOM: 'xxx' } ], [ { AUPRE: 'Prénom', AUNOM: 'Nom' } ], [ { AUPRE: 'Prénom', AUNOM: 'Nom' } ], [ { AUPRE: 'Prénom', AUNOM: 'Nom' } ] ] (2nd call, no error) [ [ RowDataPacket { AUPRE: 'xxx', AUNOM: 'xxx' } ], [ RowDataPacket { AUPRE: 'xxx', AUNOM: "xxx" } ], [ RowDataPacket { AUPRE: 'xxx', AUNOM: 'xxx' } ], [ RowDataPacket { AUPRE: 'xxx', AUNOM: 'xxx' } ], [ RowDataPacket { AUPRE: 'xxx', AUNOM: "xxx" } ], [ RowDataPacket { AUPRE: 'xxx', AUNOM: 'xxx' } ], ]
这是我的promise包装器:
function database_promise_query(database, query){ return new Promise(res => { database.query(query, (error, results, fields) => { if(error) {res(undefined); console.log(error)} res(results); }) }) }
然而,像这样在路由器之外调用这个函数却非常顺利:
(async () => { await get_works(0, 10); await get_works(10, 10); await get_works(20, 10); await get_works(30, 10); })()
我是不是漏掉了什么?我认为所有的查询都是正确的,因为我可以得到想要的结果,问题可能在于我的异步/等待处理。感谢您能提供的所有帮助。
根据@tromgy的建议,我重写了promise包装器。
function database_promise_query(database, query){ return new Promise((res, rej) => { database.query(query, (error, results, fields) => { if(error) {rej(error); throw new Error(error)} console.log("Received response", results) res(results); }) }) }
然而,拒绝从未发生(这是合理的,因为数据库中没有匹配的数据)。为了清理日志,我禁用了另一个使用不同数据库连接的类似请求的路由器。删除这个路由器也解决了这个bug。我不知道这是怎么可能的(也许一个变量被声明为全局的,所以我会寻找这种问题)。
如图所示,问题是一个共享的循环计数器。我的一个同事在迭代之前忘记添加
let
关键字,所以 for 循环跳跃了数值。我现在讨厌这个 JavaScript 特性。谢谢帮助!