2017-02-22 56 views
1

Я использую Node версию 7.6.0, чтобы опробовать встроенную функцию async и ждать.Функция Async никогда не возвращает

Я пытаюсь понять, почему мой асинхронный вызов просто висит никогда не решает.

модуль 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) 

Я могу видеть, что запрос был успешным в модуле НЛП

Console log output

Edit: Added console.log statement to response body

Console output on the actual response.body

Log statement

+0

Вы пытались поставить «асинхронный» на все функции, которые вы пытаетесь «подождать»? И поэтому постарайтесь добавить «ожидание» перед «новым обещанием». – Gilsdav

+0

@ Gilsdav - вы не «ожидаете нового обещания» - асинхронный/ждущий синтаксический сахар для Promises –

+0

какой из других сообщений console.log отображается? Ваша логика кажется звуковой –

ответ

3

Наиболее вероятной причиной является ошибка в 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 в обещаниях, а затем всегда 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; 
} 

По общему правилу я считаю, что это лучший практик:

  • Держи заверяли низкий level - имеют Promise функции обертки для ваших обратных вызовов rest и redis.
  • Удостоверьтесь, что ваши обещания reject с new Error, когда что-то пошло не так. Если Promise не resolve и не reject, тогда ваш код останавливается.
  • Каждый вызов к одному из этих оберток обещание должно быть await
  • try - catch прямо в верхней части - до тех пор, как каждый Promise является await -ed какую-либо ошибку, брошенную любой из них будет в конечном итоге на верхнем уровне catch

Большинство вопросов будет либо:

  • у вас есть Promise, что может не resolve или reject.
  • Вы звоните async function или Promise без await.