异步函数永远不会返回

时间:2017-02-22 21:36:41

标签: javascript node.js promise async-await ecmascript-2017

我正在使用Node版本7.6.0来尝试本机异步并等待功能。

我正在试图找出为什么我的异步调用只是悬挂从未实际解决。

NLP模块:

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 output

Edit: Added console.log statement to response body

Console output on the actual response.body

Log statement

1 个答案:

答案 0 :(得分:7)

最可能的原因是你没有捕捉到的Promise错误。除了顶级调用方法之外,我觉得有必要避免使用try - catch,如果方法可以await - 它几乎总是应该是。

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

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方法包装在promises中,然后始终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;
}

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

  • 保持明确的承诺低级别 - 为Promiserest回调设置redis个包装函数。
  • 当出现问题时,请确保您的承诺rejectnew Error一致。如果Promise没有resolve而没有reject,那么您的代码就会停在那里。
  • 对其中一个promise包装器的每次调用都应该有await
  • try - catch就在顶部 - 只要每个Promise都是await - 任何错误引发的任何错误都会在最高级别结束catch

大多数问题都是:

  • 您的Promise可能无法resolvereject
  • 您呼叫async functionPromise没有await