【问题标题】:How to stop promise chain after resolve?解决后如何停止承诺链?
【发布时间】:2017-02-18 17:13:24
【问题描述】:

我想在通过某些条件解决后停止 Promise 链。下面的代码可能有助于理解我在说什么。

function update(id, data) {
    return new Promise((resolve, reject) => {
        let conn;

        pool.get()
        .then((db) => {
            conn = db;

            if(Object.keys(data).length === 0) {
                return resolve({ updated: 0 });
            }
            else {
                return generateHash(data.password);
            }
        })
        .then((hash) => {
            conn.query("UPDATE ... ", (err, queryResult) => {
                if(err) {
                    throw err;
                }

                resolve({ updated: queryResult.affectedRows });
            });
        })
        .catch((err) => { ... })
    });
}

请注意,pool.get() 是承诺包装的 API,用于从我制作的 MySQL 模块获取连接池。

我想要做的是更新用户数据。为了节省服务器资源,如果没有数据要更新,我避免更新(Object.keys(data).length === 0)。

当我尝试这段代码时,即使没有要更新的数据,第二次 then(update db) 也总是发生!

我读了this post,但没有用。为什么当我调用“return resolve();”时承诺链没有停止?以及如何正确停止它?我真的很喜欢使用 Promises,但有时,这种事情会让我发疯。非常感谢帮助我解决这个问题。谢谢!

附:反正我用的是node v6.2.2。

【问题讨论】:

  • 首先,您使用的是 Promise 构造函数反模式......其次,在链的一部分中解析保证会落到下一个 .then - 这就是 Promise 链的工作原理!
  • 你可以在这里得到帮助stackoverflow.com/questions/20714460/…
  • 为什么要等到pool.get之后再检查传入的data是否没有密钥?
  • @torazaburo - 这将是下一个hash 回调中hash 的值
  • 虽然...hash好像根本没用过

标签: javascript node.js promise


【解决方案1】:

为什么当我调用“return resolve();”时,promise 链没有停止?

您已经从当前的then 回调中返回并履行了外部承诺。但这并没有“停止”任何事情,那么then 链仍将继续通过回调的返回值进行解析。

以及如何正确停止它?

您需要put the then call inside the if 才能应用该条件:

pool.get()
.then((db) => {
    …
    if (Object.keys(data).length === 0) {
        …({ updated: 0 });
    } else {
        return generateHash(data.password)
        .then((hash) => {
            conn.query("UPDATE ... ", (err, queryResult) => {
                …
            });
        })
    }
})
.catch((err) => { ... })

无论如何,您都应该避免使用Promise constructor antipattern!你应该只使用promisify query 方法:

function query(conn, cmd) {
    return new Promise((resolve, reject) => {
        conn.query(cmd, (err, queryResult) => {
            if (err) reject(err); // Don't throw!
            else resolve(queryResult);
        });
    });
}

然后使用它:

function update(id, data) {
    return pool.get()
    .then(conn => {
        if (Object.keys(data).length === 0) {
            conn.close(); // ???
            return { updated: 0 };
        } else {
            return generateHash(data.password)
            .then(hash => {
                return query(conn, "UPDATE ... ")
            }).then(queryResult => {
                conn.close(); // ???
                return { updated: queryResult.affectedRows };
            }, err => {
                …
                conn.close(); // ???
            });
        }
    });
}

请注意,如果您事先知道不会进行任何查询,则从池中获取连接可能没有意义,因此您可能应该将 if 放在顶层:

function update(id, data) {
   if (Object.keys(data).length === 0) {
       return Promise.resolve({ updated: 0 });
    } else {
       return pool.get()
       .then(conn => {
            return generateHash(data.password)
            .then(hash => {
                return query(conn, "UPDATE ... ")
            }).then(queryResult => {
                conn.close(); // ???
                return { updated: queryResult.affectedRows };
            }, err => {
                …
                conn.close(); // ???
            });
        });
    }
}

【讨论】:

  • hmmm return resolve({ updated: 0 }); ... Promise.resolve 也许?
  • @JaromandaX Dunno,这是我只关注if/then 嵌套的未清理版本
  • 你错过了conn.query(cmd, (err, queryResult) => {中的=>
  • return generateHash(data.password) 之后有一个流浪的; - ... 这也假设generateHash 返回一个承诺,不是吗?
  • @JaromandaX 是的,这是假设——否则 OP 就不必使用 then 链,对吗?顺便说一句,请随时通过编辑直接修复任何错别字
【解决方案2】:

这是使用if 语句的好情况:

function update(id, data) {
    if (Object.keys(data).length === 0) {
        return Promise.resolve({ updated: 0 }); 
    }

    let conn;

    return pool.get()
        .then((db) => {
            conn = db;

            return generateHash(data.password);
        })
        .then((hash) => {
            return new Promise(function (resolve, reject) {
                conn.query("UPDATE ... ", (err, queryResult) => {
                    if(err) {
                        reject(err);
                    }

                    resolve({ updated: queryResult.affectedRows });
                });
            });
        })
        .catch((err) => { ... })
}

【讨论】:

  • $q.when 替换为Promise.resolve,将$q(... 替换为new Promise(... - 因为没有迹象表明问题中正在使用这个$q
  • @JaromandaX 谢谢。出于某种原因,我认为这是一个 Angular 问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-29
  • 1970-01-01
  • 2016-04-05
  • 2020-09-07
  • 1970-01-01
相关资源
最近更新 更多