asynchronous函数永远不会返回
我使用节点版本7.6.0来尝试本地asynchronous并等待function。
我试图找出为什么我的asynchronous调用悬挂从未真正解决。
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语句到响应正文
最有可能的原因是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方法都包含在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
包装函数为您的rest
和redis
callback。 - 确保您的承诺
reject
与new Error
出现问题时。 如果Promise
没有resolve
,并且不reject
那么你的代码就停在那里。 - 每个对这些诺言包装器之一的调用都应该
await
-
try
catch
最上层 – 只要每一个Promise
都await
任何错误都会抛到顶层。
大多数问题将是:
- 你有一个
resolve
或reject
的Promise
。 - 您可以在不
await
情况下调用async function
或Promise
。