5

我正在使用 Node 版本 7.6.0 来试用本机 async 和 await 功能。

我试图弄清楚为什么我的异步调用只是挂起从未真正解决。

自然语言处理模块:

const rest = require('unirest')
const Redis = require('ioredis')
const redis = new Redis()
const Promise = require('bluebird')
const nlp = {}
nlp.queryCache = function(text) {
    return new Promise(function(resolve, reject) {
        redis.get(text, (err, result) => {
            if (err) {
                console.log("Error querying Redis: ", err)
                reject(new Error("Error querying Redis: ", err))
            } else {
                if (result) {
                    let cache = JSON.parse(result)
                    console.log("Found cache in Redis: ", cache)
                    resolve(cache)
                } else {
                    resolve(null)
                }
            }
        })
    })
}

nlp.queryService = function(text) {
    console.log("Querying NLP Service...")
    return new Promise(function(resolve, reject) {
        rest.get('http://localhost:9119?q=' + text)
            .end((response) => {
                redis.set(text, JSON.stringify(text))
                resolve(response.body)
            })
    })
}

nlp.query = async function(text) {
    try {
        console.log("LET'S TRY REDIS FIRST")
        let cache = await nlp.queryCache(text)
        if (cache) {
            return cache
        } else {
            let result = await nlp.queryService(text)
            console.log("Done Querying NLP service: ", result)
            return result
        }
    } catch (e) {
        console.log("Problem querying: ", e)
    }

}
module.exports = nlp

模块消费者:

const modeMenu = require('../ui/service_mode')
const nlp = require('../nlp')
const sess = require('../session')
const onGreetings = async function(req, res, next) {
    let state = sess.getState(req.from.id)
    if (state === 'GREET') {        
        let log = { 
            middleware: "onGreetings"           
        }
        console.log(log)
        let result = await nlp.query(req.text)
        console.log("XXXXXXXX: ", result)
        res.send({reply_id: req.from.id, message: msg})

    } else {
        console.log("This query is not not normal text from user, calling next()")
        next()
    }
};
module.exports = onGreetings;

我无法让代码继续执行以下行:

console.log("XXXXXXXX: ", result) 

我可以看到在 NLP 模块中查询成功了

控制台日志输出

编辑:在响应正文中添加了 console.log 语句

实际 response.body 上的控制台输出

日志语句

4

1 回答 1

8

最可能的原因是您没有捕捉到的 Promise 错误。我发现它有助于避免try-catch除了顶级调用方法之外的所有方法,如果一个方法可以await-ed 它几乎总是应该的。

在你的情况下,我认为问题出在:

nlp.queryService = function(text) {
    console.log("Querying NLP Service...")
    return new Promise(function(resolve, reject) {
        rest.get('http://localhost:9119?q=' + text)
            .end((response) => {
                redis.set(text, JSON.stringify(text)) // this line is fire and forget
                resolve(response.body)
            })
    })
}

特别是这一行:redis.set(text, JSON.stringify(text))- 该行正在调用一个函数,并且没有发现任何错误。

解决方法是将所有 Redis 方法包装在 Promise 中,然后始终使用await它们:

nlp.setCache = function(key, value) {
    return new Promise(function(resolve, reject) {
        redis.set(key, value, (err, result) => {
            if (err) {
                reject(new Error("Error saving to Redis: ", err));
            } else {
                resolve(result);
            }
        });
    })
}

nlp.queryService = async function(text) {
    console.log("Querying NLP Service...")
    const p = new Promise(function(resolve, reject) {
        rest.get('http://localhost:9119?q=' + text)
            .end((response) => { resolve(response.body) });

        // This is missing error handling - it should reject(new Error... 
        // for any connection errors or any non-20x response status 
    });

    const result = await p;

    // Now any issue saving to Redis will be passed to any try-catch
    await nlp.setCache(text, result);
    return;
}

作为一般规则,我发现最好的做法是:

  • 保持显式承诺低级别 -为您的和回调提供Promise包装函数。restredis
  • 确保在出现问题时兑现您的reject承诺new Error。如果 aPromise没有resolve并且没有,reject那么您的代码将停在那里。
  • 对这些承诺包装器之一的每次调用都应该有await
  • try-catch就在顶部 - 只要每个都Promiseawait-ed 他们中的任何一个抛出的任何错误都将最终出现在顶层catch

大多数问题要么是:

  • 你有一个Promise可能失败的resolvereject
  • 你打电话给一个async functionPromise没有await
于 2017-02-24T12:19:24.930 回答