sqlite 无法使用承诺在Java脚本中对数组进行ForEach操作,控制台显示奇怪的数组结果

nnvyjq4y  于 2022-11-15  发布在  SQLite
关注(0)|答案(1)|浏览(166)

我正试着做两件事:

  • 从数据库中获取唯一对话ID列表
  • 获取每个对话的最新消息

但是,我不能使用返回的消息迭代数组。我已经尝试将代码的两个部分分开,在不同的函数中。从另一个调用其中一个,现在使用.Then语句顺序调用这两个语句,但都不起作用。如果能帮上忙我会很感激的。
这是NodeJS,带有SQLite3
这是控制台返回时显示的内容:

以下是获取消息的代码:

function getConversationsList(idList) 
{
    
    var c = [];
        return new Promise((resolve) => {
            
            idList.forEach((id => {
                
                db.all("SELECT * FROM messages WHERE (conversationId = ? AND isBroadcast = 0 AND isWarmup = 0) ORDER BY messageTime DESC LIMIT 1",{1:id},function(err,row) {
                    if(err) 
                    {
                        console.log(err.message);
                        return resolve(err);
                    }
                    row.forEach((d => {
                        console.log(d);
                        c.push(d);
                    }))
                    
                 
                }); 
                
                

            }))
            resolve(c);
        });
    
    
    
}
function convoidlist() 
{
    idlist = [];
    return new Promise((resolve) => { 
        db.all("SELECT DISTINCT conversationId FROM messages",{},function(err,rows){
            if(err) 
            {
                console.log(err)
            }
            rows.forEach((row) => {
                idlist.push(row.conversationId);
            });
            resolve(idlist);
        })

    });
}

这是试图循环通过它们的代码,没有错误,但循环永远不会进入...

function refreshConversations() 
    {
        convoidlist().then((idlist) => {
            getConversationsList(idlist).then((f) => {
            
            console.info(f);
            var chtml = "";
            
            
            f.forEach((e,index,array) => {
                console.info(e[index]);
                var newc = `
                <div data-id="${e.conversationId}" style="width:100%;padding:10px;margin-bottom:20px;" class="border">
                    <div width="100%" style="font-size:0.8em;"><span style="width:50%;text-align:left">${e.messageFrom}</span><span style="width:40%;">${e.messageTime}</span></div>
                    <div width="100%" style="height:100px;overflow:hidden;">${e.messageBody}</div>
                    </div>
                
                `;
                chtml = chtml + newc;
                console.log(newc);
            });
            console.log(chtml);
            document.getElementById('conversationlist').innerHTML = chtml;
        
        });
    });
    }

我知道这有点乱,它清楚多了,但我已经试了很多。如有任何帮助,我们不胜感激。

ttisahbt

ttisahbt1#

您将承诺、常规的异步回调和.forEach()混合在一起,这使得编写适当的异步代码变得非常困难。最好先中止任何异步操作。
如果您无法访问支持承诺的sqlite3版本,那么您可以简化需要使用的特定操作(就像我在这里所做的那样)。这最好集中在一个地方进行,但由于您没有显示该级别的代码上下文,所以在这个特定的问题中,我只是在本地进行。
然后,避免在循环中将.forEach()与异步操作一起使用,因为.forEach()以任何方式都不是承诺感知或异步感知的。它只是愉快地运行它的循环,而不等待任何异步操作完成,这很难管理。
以下是一种经过简化和重组的做事方式:

const { promisify } = require("util");

async function getConversationsList(idList) {
    // promisify db.all
    db.allP = promisify(db.all);

    const data = [];
    for (let id of idList) {
        const rows = await db.allP("SELECT * FROM messages WHERE (conversationId = ? AND isBroadcast = 0 AND isWarmup = 0) ORDER BY messageTime DESC LIMIT 1", { 1: id });
        data.push(...rows);
    }

    return data;
}

async function convoidlist() {
    db.allP = promisify(db.all);
    const rows = await db.allP("SELECT DISTINCT conversationId FROM messages", {});
    return rows.map(row => row.conversationId);
}

async function refreshConversations() {
    try {
        const idlist = await convoidlist();
        const conversations = await getConversationsList(idlist);
        console.info(conversations);

        let html = conversations.map(e => {
            return `
            <div data-id="${e.conversationId}" style="width:100%;padding:10px;margin-bottom:20px;" class="border">
                <div width="100%" style="font-size:0.8em;"><span style="width:50%;text-align:left">${e.messageFrom}</span><span style="width:40%;">${e.messageTime}</span></div>
                <div width="100%" style="height:100px;overflow:hidden;">${e.messageBody}</div>
                </div>

            `
        });
        document.getElementById('conversationlist').innerHTML = html.join("/n");
    } catch (e) {
        console.log(e);
        // decide what to show the user here if there was an error
    }
}

备注:
1.添加db.allP()作为db.all()的简化版本。
1.只对异步控制流使用Promise。
1.在循环中不使用任何带有异步操作的.forEach()。只使用承诺和使用await的常规for循环控制事情要容易得多。
1.在refreshConversations()中,您调用convoidlist(),但从不使用其结果。
1.将错误上报集中在refreshConversations()中。低级函数应返回数据或错误。更高级别的函数决定如何处理错误以及何时记录错误。

相关问题