продолжить субциклы после ошибки внутри обещания - PullRequest
0 голосов
/ 29 сентября 2018

У меня серьезные сомнения в том, что код, который я пишу, является эффективным / лучшим способом достижения моей цели.

У меня есть обещание, которое делает запрос SQL, после его завершения я перебираю циклмассив и его подмассивы + объекты.Даже если какой-либо из подциклов завершится неудачей по какой-либо конкретной причине, я хочу, чтобы внутренние циклы продолжали выполняться до тех пор, пока весь массив не будет закольцован.Прямо сейчас у меня есть ад "попробуй / поймай", и я сомневаюсь, что это правильный способ сделать это.Тем не менее, я должен сказать, что он работает, как и ожидалось, но насколько он плох?

new Promise((resolve, reject) => {
    sqlConnection.execute(
    'INSERT INTO pms (userId, message, conversationId) VALUES (?, ?, ?)',
        [userid, receivedMsg, receivedConvId],
        function(err, results) {
            if (err) throw err;
            resolve("DEBUG: PM from "+username+" into conv "+receivedConvId+" was sucessfully inserted to DB");
        }   
    );  
}).then(() => {
    users.forEach(function(userobj, i, arr) {
        try {
            if (userobj.memberof.includes(receivedConvId)) {
                let rcptUsername = userobj.username;    
                let rcptUserid = userobj.userid;
                debug(rcptUsername+" is member of the group "+receivedConvId);
                Object.keys(userobj.sessions).forEach(function(session) {
                    try {
                    userobj.sessions[session].forEach(function(wsConn) {
                        try {   
                            debug("DEBUG: Broadcasting message to "+rcptUsername+" for connections inside session "+session);
                            wsConn.send(JSON.stringify(msgToSend));
                        } catch(err) {
                            errorHandler(err);
                        }   
                    }); 
                    } catch(err) {
                    errorHandler(err);
                }   
            }); 
        }   
    } catch(err) {
        errorHandler(err); 
     }
});
}).catch((err) => {
    debug(err);
}).then(() => {
    debug("INFO: Message broadcast finished");
});

Массив, который я перебираю, может выглядеть так:

[ 
{ username: 'Root',
    userid: '1',
    memberof: [ 1, 2, 3 ],
    sessions: 
        { 
            pvkjhkjhkj21kj1hes5: [Array],
            '4duihy21hkk1jhhbbu52': [Array] 
        } 
},
{ 
    username: 'Admin',
    userid: '2',
    memberof: [ 1, 2, 4 ],
    sessions: 
        { 
            cg2iouoiuiou111uuok7: [Array],
            sl1l3k4ljkjlkmmmmkllkl: [Array] 
        } 
} 
]

Благодарен любомусоветы.

1 Ответ

0 голосов
/ 30 сентября 2018

Предполагая, что wsConn - это https://github.com/websockets/ws веб-сокет - тогда используемый вами код в любом случае только "обнаружит" немедленные ошибки - любые ошибки записи в сокет не будут обнаружены

Вы также будете выводить«INFO: Передача сообщений завершена» до завершения любого из wsConn.send - потому что он асинхронный

К счастью, .send имеет обратный вызов, который вызывается при ошибках или успешном завершении после завершения - это решает обе проблемы

Использование обещаний - хорошая идея, за исключением того, что вы не использовали обещания ни для чего, кроме начального выполнения SQL, поэтому вы оказались в аду вложений

Я довольно уверен (без вашего полного кода, я не уверен), что следующий код не только будет работать, но и будет гораздо меньше вложен

new Promise((resolve, reject) => {
    sqlConnection.execute(
        'INSERT INTO pms (userId, message, conversationId) VALUES (?, ?, ?)',
        [userid, receivedMsg, receivedConvId],
        (err, results) => {
            if (err) {
                return reject(err);
            }
            resolve("DEBUG: PM from " + username + " into conv " + receivedConvId + " was sucessfully inserted to DB");
        }
    );
}).then(() => {
    const allConnectionsArray = users
    .filter(({memberof}) => memberof.includes(receivedConvId)) // filter out any userobj we aren't going to send to
    .map(({rcptUsername, rcptUserid, sessions}) => {
        debug(rcptUsername + " is member of the group " + receivedConvId);
        const userSessionsArray = Object.entries(sessions).map(([session, value]) => {
            return value.map((wsConn, index) => {
                return { wsConn, rcptUserid, rcptUsername, session, index };
            })
        });
        return [].concat(...userSessionsArray); // flatten the array
    });
    const promises = [].concat(...allConnectionsArray) // flatten the array
    .map(({ wsConn, rcptUserid, rcptUsername, session, index }) => {
        debug("DEBUG: Broadcasting message to " + rcptUsername + " for connections inside session " + session);
        return new Promise((resolve) => {
            wsConn.send(JSON.stringify(msgToSend), err => {
                if (err) {
                    return resolve({ rcptUserid, rcptUsername, session, index, err });
                }
                resolve({ rcptUserid, rcptUsername, session, index, err: false });
            });
        });
    });
    return Promise.all(promises);
}).then(results => {
    /* results is an array of {
        rcptUserid
        rcptUsername
        session
        index //(index is the ordinal position in user.sessions array
        err //(===false if success)
    }
    */
    debug("INFO: Message broadcast finished");
}).catch(error => {
    // the only error caught here would be in the `return reject(err);` in the sql execute,
    // because any failure in wsConn.send is a resolved promise (with an error property)
    // unless I'm not seeing something obvious, they are the only possible places an error could be thrown anyway
});
...