NodeJS - бесконечный вызов функций обещания

1

Я ищу способ бесконечно вызывать функции с обещаниями. Я попробовал 2 сценария, один работает, а другой нет. Цель кода, который не работает, заключается в следующем: получить данные из API и затем сохранить их в базе данных.

Я изучаю обещания, может кто-нибудь объяснить мне, почему он работает, а другой нет? Ниже моих кодов

Рабочий код Функция вызывается только один раз, я хочу, чтобы она называлась бесконечно

const request = require('request') //node to facilitate http request
var nano    = require('nano')('http://admin:12345@localhost:5984'); //connect to couchdb using id and password
var db_name  = nano.db.use('bitfinex'); //couchdb database name
var ltc_url = 'https://api.bitfinex.com/v1/pubticker/ltcusd' //entry point
var nonce = new Date().toISOString()  //gives a unique id
                      .replace(/T/, ' ')    // replace T with a space
                      .replace(/\..+/, '')     // delete the dot and everything after

let cleanTheRoom = function() {
      return new Promise(function(resolve, reject) {
        resolve('Cleaned the Room, ');
      });
    };

  let removedTheGarbage = function(msg) {
    return new Promise(function(resolve, reject) {
      resolve(msg + 'removed the garbage, ');
    });
  };

  let getIcecream = function(msg) {
    return new Promise(function(resolve, reject) {
      resolve(msg +'got icecream.');
    });
  };

setInterval(function(){
  cleanTheRoom()
    .then(removedTheGarbage)
    .then(getIcecream)
    .then(function(msg) {
    console.log(msg );
  });
}, 2000);

Неудачный код

const request = require('request') //node to facilitate http request
    var nano    = require('nano')('http://admin:12345@localhost:5984'); //connect to couchdb using id and password
    var db_name  = nano.db.use('bitfinex'); //couchdb database name
    var ltc_url = 'https://api.bitfinex.com/v1/pubticker/ltcusd' //entry point
    var nonce = new Date().toISOString()  //gives a unique id
                          .replace(/T/, ' ')    // replace T with a space
                          .replace(/\..+/, '')     // delete the dot and everything after

// get current litecoin price from Bitfinex

function getLtcPrice(){
  return new Promise(function(resolve, reject){
    request.get(ltc_url,
        function (error, response, body) {
        var rep = JSON.parse(body);
        var ltc_price = rep.ask;
          resolve (ltc_price)
        if (error){
          reject(ltc_price)
          }
      });
    })
  }

//save current litecoin price to the database

function saveLtcPrice (ltc_price){
      return new Promise(function(resolve, reject){
        resolve(
        db_name.insert({ _id: nonce, currency:"Litecoin", price: ltc_price},
           function(err, body) {
             if (!err)
             console.log(" ltc price : "+ ltc_price +", uploaded to the database ");
          })
          )
      });
    }

setInterval(function(){
  getLtcPrice()
    .then(function(ltcPrice){
      saveLtcPrice(ltcPrice);
    });
}, 2000);
  • 1
    какие сообщения об ошибках вы получаете. Можете ли вы дать немного больше информации?
  • 1
    Что, если предыдущий вызов еще не был завершен, когда обработчик для setInterval снова запущен? Стоит ли ждать завершения предыдущего запроса (запросов)?
Показать ещё 1 комментарий
Теги:
promise
setinterval

4 ответа

1
Лучший ответ

Перепишите вашу saveLtcPrice, чтобы разрешить ее после завершения вставки:

// get current litecoin price from Bitfinex
function getLtcPrice(){
   return new Promise(function(resolve, reject){
       request.get(ltc_url, function (error, response, body) {
           if (error) reject(error)

           var rep = JSON.parse(body);
           var ltc_price = rep.ask;
           resolve (ltc_price)
       });
   })
}

//save current litecoin price to the database
function saveLtcPrice (ltc_price){
    return new Promise(function(resolve, reject){
        db_name.insert({
            _id: nonce,
            currency:"Litecoin",
            price: ltc_price
        }, function(error, body) {
            if(error) reject(error)

            console.log(" ltc price : "+ ltc_price +", uploaded to the database ");
            resolve(body)
      })
  });
}

Promise.resolve().then(function resolver() {
    return getLtcPrice().then(function(ltcPrice){
        return saveLtcPrice(ltcPrice);
    }).then(resolver)// both functions ended, call them again
}).catch((error) => {
    console.log("Error: " + error);
});
  • 1
    Я считаю, что рекурсивная функция без использования setTimeout или setImmediate приведет к stack overflow . Я могу ошибаться, если это завернуто в обещание, мне сейчас любопытно.
  • 0
    Вау, не знал, спасибо!
Показать ещё 4 комментария
1

я вижу 2 ошибки в вашем падающем коде. В функции getLtcPrice вы должны проверить наличие ошибок перед их решением.

function getLtcPrice(){
  return new Promise(function(resolve, reject){
    request.get(ltc_url, function (error, response, body) {
      if (error) { // check for errors immediatly
        reject(ltc_price)
        return
      }
        var rep = JSON.parse(body);
        var ltc_price = rep.ask;
        resolve(ltc_price)
      });
    })
  }

в функции saveLtcPrice вы всегда решаете передачу вызова функции async. Это не имеет смысла. Вы должны делать точно так же, как в функции getLtcPrice, поэтому:

function saveLtcPrice (ltc_price) {
      return new Promise(function(resolve, reject) {
        db_name.insert({ _id: nonce, currency:"Litecoin", price: 
          ltc_price},function(err, document) { //changed variable name "body" to "document". it just a convention, this is not the body of an http request, this is an object inside a database
             if (err) {
               reject(err)
               return
             }

             console.log(" ltc price : "+ ltc_price +", uploaded to the database ");
             resolve(document)
          })
          )
      });
    }

Наконец, вы должны ловить ошибки внутри вашей функции setInterval

  • 0
    Вы по-прежнему неправильно используете getLtcPrice : вам нужно else чтобы вызывать только одну ветку: если есть ошибка, вероятно, нет тела для анализа.
  • 0
    @ Дункан не соответствует действительности. если вы отклоняете предложение, выполнение кода немедленно останавливается.
Показать ещё 10 комментариев
0

Добавление еще одного ответа:

// get current litecoin price from Bitfinex
const getLtcPrice = (ltc_url) =>
  new Promise(
    (resolve, reject) =>
      request.get(
        ltc_url,
        (error, response, body) =>
          error
            ? reject(error)
            : resolve(JSON.parse(body).ask)
      )
  );

//save current litecoin price to the database
const saveLtcPrice = (ltc_price) =>
  new Promise(
    (resolve, reject) =>
      db_name.insert(
        { _id: nonce, currency: "Litecoin", price: ltc_price },
        (err, body) =>
          err
            ? reject(err)
            : console.log(" ltc price : " + ltc_price + ", uploaded to the database ")
              || resolve(body)
    )
  );

const keepGettingPrice = () => {
  const rec =
    p =>
      //if previous saves were not finished then wait for it to finish
      p = p.then(
        //!!!!!!!!!!!!! where does ltc_url come from?
        _ => getLtcPrice(ltc_url)
      ).then(
        saveLtcPrice
      ).then(
        undefined,
        //handle the error
        err=>console.warn("failed one:",err,)
      )
      .then(
        x=>new Promise((r)=>setTimeout(r,2000))
      );
  return rec(Promise.resolve());
};
keepGettingPrice();
  • 1
    Не могли бы вы использовать правильное выражение if с блоками для побочных эффектов? console.log(…) && даже не работает.
  • 0
    @ Берги Да, забыл console.log возвращает неопределенное. Обычно просто отжимайте их для отладки, чтобы мне не нужно было добавлять {} для функции.
0

Функция saveLtcPrice имеет очень странное размещение вызова для resolve

function saveLtcPrice (ltc_price){
  return new Promise(function(resolve, reject){
    resolve( /* <--- HERE */
    db_name.insert({ _id: nonce, currency:"Litecoin", price: ltc_price},
       function(err, body) {
         if (!err)
         console.log(" ltc price : "+ ltc_price +", uploaded to the database ");
      })
      )
  });
}

Возможно, вы должны вызвать решение после завершения операции с базой данных в последнем обратном вызове.

function saveLtcPrice (ltc_price){
  return new Promise(function(resolve, reject){
    db_name.insert({ _id: nonce, currency:"Litecoin", price: ltc_price},
       function(err, body) {
         if (!err) {
           resolve(body) /* <-- Move to here */
           console.log(" ltc price : "+ ltc_price +", uploaded to the database ");
         } else {
           reject(err);
         }
       })
  });
}

Похоже, что вы пытаетесь разрешить с помощью вызова операции async базы данных. Поскольку эта операция с базой данных принимает обратный вызов в качестве параметра, очень маловероятно, что ваше обещание разрешено с помощью чего-либо иного, кроме undefined.

Убедитесь, что вы правильно выполнили свое обещание, и попытайтесь использовать .catch() чтобы вы могли поймать свои ошибки, иначе найти источник проблем с кодом в обещаниях может быть сложно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню