函数运行后数组为空?

app.post('/api/edit-profile', regularFunctions, async function (req, res) {

    let email = req.body.email

    let password_current = req.body.password_current

    connection.query('SELECT * FROM accounts WHERE id = ?', req.body.id, async function (err, results) {

        if (results.length > 0) {

            bcrypt.compare(password_current, results[0].password, async function (err, isMatch) {

                if (err) {

                    res.send('Unable to save settings')

                    res.end();

                    throw err

                } else if (!isMatch) {

                    res.send('Password doesn\'t match.')

                    res.end();

                } else {

                    let changed = []

                    // Password matches

                    if (req.body.password_new) {

                        let newPassword = req.body.password_new

                        let hashed_password = await hashPassword(newPassword)

                        connection.query('UPDATE accounts SET password = ? WHERE id = ?', [hashed_password, req.body.id], async function (error, results) {

                            if (results.affectedRows && results.affectedRows > 0) {

                                changed.push('password')

                            } else {

                                res.send('Unable to save settings')

                                res.end();

                            }

                        })

                    }



我知道这对一些专家编码员来说似乎是一个非常简单的问题,但我对整个异步和同步的事情有点陌生。为什么“已更改”数组即使在函数运行后被推送到也不会更新?我想做的是让它只返回一个可以在客户端显示的字符串,但它似乎并没有改变它,只返回“成功改变,”


UYOU
浏览 105回答 2
2回答

德玛西亚99

这个功能让我感到困惑,因为它有很多责任,但我发现了问题:该connection.query方法是非阻塞的,这意味着它不会等待它的执行结束以前进到下一条指令。当您使用异步方法和时Promise,最好尝试保持方法的一致性(避免混合回调函数和async/ await)。async如果使用/ ,我已经重构了它应该是什么样子await:app.post('/api/edit-profile', regularFunctions, async function (req, res) {    let email = req.body.email    let password_current = req.body.password_current    let results = await executeQuery(connection, 'SELECT * FROM accounts WHERE id = ?', [req.body.id]);    if (results.length > 0) {        let isMatch = await comparePassword(password_current, results[0].password);        if (!isMatch) {            throw new Error(`Password doesn't match`);        }        let changed = []        // Password matches        if (req.body.password_new) {            let newPassword = req.body.password_new            let hashed_password = await hashPassword(newPassword)            let results = await executeQuery(connection, 'UPDATE accounts SET password = ? WHERE id = ?', [hashed_password, req.body.id]);            if (results.affectedRows && results.affectedRows > 0) {                changed.push('password')            } else {                throw new Error('Unable to save settings');            }        }        if (req.body.license_key) {            let newKey = req.body.license_key            let response = await axios.get(`https://voltcloud.net/api/hosting/check-key/${newKey}`, {                headers: {                    authorization: '<redacted>'                }            });            let data = response.data            if (typeof data === 'object') {                if (data.active === 1) {                    let response = await axios({                        method: 'post',                        url: `https://voltcloud.net/api/hosting/activate-key/${newKey}`,                        headers: {                            authorization: '<redacted>'                        }                    })                    if (response.data === 'Success') {                        let results = await executeQuery(connection, 'UPDATE accounts SET license_key = ? WHERE id = ?', [newKey, req.body.id]);                        if (results.affectedRows && results.affectedRows > 0) {                            changed.push('license key')                        } else {                            throw new Error('Unable to save settings');                        }                    } else if (data === 'License already active!') {                        throw new Error('License key is already active!');                    } else if (data === 'Failed to update key.') {                        throw new Error('Unable to save settings');                    } else {                        throw new Error('Unable to save settings');                    }                }            }        }        let results = await executeQuery(connection, 'UPDATE accounts SET email = ? WHERE id = ?', [email,req.body.id]);        if (results.affectedRows && results.affectedRows > 0) {            changed.push('email')        } else {            throw new Error('Unable to save settings');        }        let finalTxt = 'Successfully changed, '        if (changed.length > 1) {            changed.forEach(function (txt, index) {                if (index === 0) {                    finalTxt = finalTxt + txt                } else if (index === 2) {                    finalTxt = finalTxt + `and ${txt}.`                }            })        } else if (changed.length === 1) {            finalTxt = `Successfully changed ${changed[0]}.`        }        res.send(finalTxt)        res.end();    }});function executeQuery(conn, sql, params) {    return new Promise((resolve, reject) => {        conn.query(sql, params, function (err, data) {            if (err != null) {                return reject(err);            }            return resolve(data);        });    });}function comparePassword(val1, val2) {    return new Promise((resolve, reject) => {        bcrypt.compare(val1, val2, function (err, isMatch) {            if (err != null) {                return reject(err);            }            resolve(isMatch);        });    })}请注意,我们根本没有使用回调函数,即使在我们没有基于本机的Promise函数(即 mysql 连接)的情况下,我们也委托给一个函数来代理回调以提供Promise并保持最终的一致性执行。

喵喵时光机

if原始代码在发送响应之前并没有等待两个分支完成。由于嵌套,很难在回调中构造这样的代码。尽可能使用async函数await。它允许更多的可读代码和更容易的错误处理。所以这个答案更多的是代码审查,而不是针对您的问题的简单修复。拆分出一些在其他路由中有用的通用帮助代码:// Generate errors for the web, with contextfunction responseError(message, status, data){    const error = new Error(message)    error.status = status    for (const key in data){        error[key] = data[key]    }    return error}// Turn mysql callbacks into promises (or use util.promisify)async function runQuery(query, values){    return new Promise((resolve, reject) => {        connection.query(query, values, function(error, results){            if (error) return reject(error)            return resolve(results)        })    })}async function runUpdateQuery(query, values){    const results = await runQuery(query, values)    if (!results) throw responseError('No update result', 500, { query })    if (!results.affectedRows) throw responseError('No affected rows', 400, { query })    return results}来自两个条件的代码if可以很容易地分开,以及其他帐户操作。async function apiAuthUserId(id, password){    const results = await runQuery('SELECT * FROM accounts WHERE id = ?', id)    if (!results.length) throw responseError('No account', 400, { id })    const isMatch = await bcrypt.compare(password_current, results[0].password)    if (!isMatch) throw responseError('Password doesn\'t match', 400)    return true}async function apiUpdatePassword(id, password){    let newPassword = req.body.password_new    let hashed_password = await hashPassword(newPassword)    await runUpdateQuery('UPDATE accounts SET password = ? WHERE id = ?', [hashed_password, req.body.id])    return id}async function apiUpdateEmail(id, email){    await runUpdateQuery('UPDATE accounts SET email = ? WHERE id = ?', [email, id])    return email}async function apiUpdateLicenseKey(id, licenseKey){    const response_license = await axios.get(`https://voltcloud.net/api/hosting/check-key/${licenseKey}`, {        headers: {            authorization: 'somekey'        }    })    const data = response_license.data    if (!data) {      throw responseError('No license key response data', 500, { response: response_license })    }    if (data.active !== 1) {      throw responseError('License key not active', 400,  { key: licenseKey })    }    const response_activate = await axios({        method: 'post',        url: `https://voltcloud.net/api/hosting/activate-key/${licenseKey}`,        headers: {            authorization: 'somekey'        }    })    switch (response_activate.data){        case 'License already active!':            throw responseError('License key is already active!', 400, { response: response_activate })        case 'Failed to update key.':            throw responseError('Unable to save settings!', 400, { response: response_activate })        case 'Success':            await runUpdateQuery('UPDATE accounts SET license_key = ? WHERE id = ?', [licenseKey, req.body.id])            return licenseKey        default:            throw responseError('Unable to save settings!', 500, { response: response_activate })    }}这样您的路由代码就可以更简洁一些,并显示需要完成的工作,而不是如何完成所有工作。app.post('/api/edit-profile', regularFunctions, async function (req, res) {    const changed = []    try {        const { id, email, password_current } = req.body        await apiAuthUserId(id, password_current)        // Password matches        if (req.body.password_new) {            await apiUpdatePassword(id, req.body.password_new)            changed.push('password')        }        // License key        if (req.body.license_key) {            await apiUpdateLicenseKey(id, req.body.license_key)            changed.push('license key')        }        await apiUpdateEmail(id, email)        changed.push('email')        let finalTxt = `Successfully changed ${changed.join(' and ')}.`        res.send(finalTxt)    }    catch (error) {        // If your not using transactions, might need to deal with partial `changed` responses here.         console.error('Error /api/edit-profile', error)        res.status(error.status||500).send(`Error: ${error.message}`)    }});
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript