NodeJS Promise 在隨機情況下傳回 undefined 值
P粉321584263
P粉321584263 2024-01-16 14:46:41
0
1
454

首先,如果這個問題已經有答案了,我很抱歉,但是我已經搜尋了這種問題,沒有找到有用的東西。

我正在開發一個使用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);
})()

我是不是漏掉了什麼?我認為所有的查詢都是正確的,因為我可以得到想要的結果,問題可能在於我的非同步/等待處理。感謝您能提供的所有協助。

編輯 1

根據@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。我不知道這是怎麼可能的(也許一個變數被聲明為全域的,所以我會尋找這種問題)。

P粉321584263
P粉321584263

全部回覆(1)
P粉063862561

如圖所示,問題是一個共享的循環計數器。我的一個同事在迭代之前忘記添加 let 關鍵字,所以 for 迴圈跳躍了數值。

我現在討厭這個 JavaScript 特性。謝謝幫忙!

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板