首先,如果這個問題已經有答案了,我很抱歉,但是我已經搜尋了這種問題,沒有找到有用的東西。
我正在開發一個使用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 特性。謝謝幫忙!