【问题标题】:Async function never returns异步函数永远不会返回
【发布时间】:2017-07-13 04:00:33
【问题描述】:

我正在使用 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模块中可以看到查询成功

Edit: Added console.log statement to response body

【问题讨论】:

  • 您是否尝试在您尝试“等待”的所有功能上放置“异步”?所以尝试在“new Promise”之前添加“await”。
  • @Gilsdav - 你没有 return await new Promise - async/await 是 Promises 的语法糖
  • 显示了哪些其他console.log 消息?你的逻辑似乎很合理
  • 大家好,感谢您的关注。如您所见@JaromandaX。只有在 Redis 中找不到 NLP 服务后,我才尝试查询它。 nlp.query() 调用的输出表明调用已成功返回,但它从未将其传递给结果变量。
  • 您似乎没有处理来自rest.get 的任何错误,在这种情况下,承诺将无限期地保持未解决(并挂起您的async function)。

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


【解决方案1】:

最可能的原因是您没有捕捉到的 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;
}

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

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

大多数问题要么是:

  • 您的 Promise 可能会失败到 resolvereject
  • 您调用async functionPromise 而不使用await

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 2016-01-16
    • 2018-04-04
    • 1970-01-01
    相关资源
    最近更新 更多