0

I have created a mini function which searches for a keyword title and returns the title with that keyword included, it gets the correct data but spams the terminal with the same error over and over again.

const request=(url,cb)=>require('node-fetch')(url).then(res=>res.text()).then(data => cb(null,null,data), cb)

function script(keyword) {
  request('https://hacker-news.firebaseio.com/v0/newstories.json?print=pretty', function(error, res, body){
    let obj = JSON.parse(body);
    for(let i = 0; i < obj.length; i++) {
      request(`https://hacker-news.firebaseio.com/v0/item/${obj[i]}.json?print=pretty`, function(error, res, body){
        let myData = JSON.parse(body);
        var s = moment.unix(myData.time).format('LLLL');
        var link = `https://news.ycombinator.com/item?id=${myData.id}`;

        if(myData.title.includes(keyword)) {
          client.hmset("requestedData", {Title: myData.title, Upvotes: myData.score, Date: s, URL: link})
          client.hgetall("requestedData", function(err, reply) {
            console.log(reply)
          })
        }
      })
    }
  })
}

script("Software")

Error => (node:15992) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3795)

Joe
  • 23
  • 6

2 Answers2

1

You need to do a catch statement on your request function. It may fail

const request=(url,cb)=>require('node-fetch')(url)
    .then(res => res.text())
    .then(data => {
         // Catching cb, it may fail too
         try{ cb(null,null,data) } catch(err){console.error(err)}
     })
    .catch(err => cb(err, null, null)) // Request went wrong.
    .catch(console.error) // Just to log if catch fails too


You also need on your function check for the error argument, don't assume it will always work.

Maxwell s.c
  • 1,583
  • 15
  • 29
  • 1
    No. OP does already pass the `cb` as the rejection handler argument to `.then()`. When it fails, it would call `cb` *twice* with the extra `catch`, which you definitely don't want. – Bergi Jun 30 '20 at 17:26
  • You're right @Bergi , fixed it. If you have an better fix, feel free to suggest it :) – Maxwell s.c Jun 30 '20 at 17:33
  • I think you meant to do `.then(data => cb(null,null,data), cb).catch(console.error)`, or `.then(data => { try { cb(null,null,data) } catch(err) { console.error(err); } }, err => { try { cb(err) } catch(err) { console.error(err); } })`. I generally [suggest to avoid `.then(…).catch(…)` for distinguishing success and error cases](https://stackoverflow.com/q/24662289/1048572). – Bergi Jun 30 '20 at 17:37
  • I'm getting another similar error now ```(node:13124) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3657)``` @Bergi – Joe Jun 30 '20 at 18:40
  • @Joe That's still exactly the same problem? You need to take a look at the line above that, where it logs the actual error that led to the unhandled rejection. – Bergi Jun 30 '20 at 20:29
  • @Bergi no, The callback not always will return an promise, so not possible to assume that. And no need to catch the first catch, since it's always the last chain (but an `.then(console.error)` could be added – Maxwell s.c Jul 01 '20 at 13:08
1

Instead of converting the promises that node-fetch gives you back to callback style1, you should embrace promises and use simple async/await:

const fetch = require('node-fetch');

async function script(keyword) {
  const response = await request('https://hacker-news.firebaseio.com/v0/newstories.json?print=pretty');
  let obj = await respose.json();
  for (let i = 0; i < obj.length; i++) {
    const response = request(`https://hacker-news.firebaseio.com/v0/item/${obj[i]}.json?print=pretty`);
    const myData = response.json();
    const s = moment.unix(myData.time).format('LLLL');
    const link = `https://news.ycombinator.com/item?id=${myData.id}`;
    if (myData.title.includes(keyword)) {
      client.hmset("requestedData", {Title: myData.title, Upvotes: myData.score, Date: s, URL: link})
      const reply = await new Promise((resolve, reject) => {
        client.hgetall("requestedData", function(err, reply) {
          if (err) reject(err);
          else resolve(reply);
        });
      });
      console.log(reply)
    }
  }
}

script("Software").catch(console.error);

1: Your cb was throwing some exception which was not handled anywhere, and rejected the promise that you ignored.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375