0

I just updated the code I had with yours. I am getting an error for headers not being defined which is odd.

No need to refactor the initial twitter pulling trends code, I am just trying to get it to work. I know the getTrends() function is pulling and topNews is only grabbing the first 5.

Any idea what I am doing wrong?

let topics = [];
let topNews = [];

function getTrends() {
  var myHeaders = new Headers();
  myHeaders.append(
    "Authorization",
    "Bearer ************"
  );
  myHeaders.append(
    "Cookie",
    'personalization_id="v1_QSZs3kHuqI6knlNtIbIchQ=="; guest_id=v1%3A159630901122767291'
  );

  var requestOptions = {
    method: "GET",
    headers: myHeaders,
    redirect: "follow",
  };

  const url =
    "https://cors-anywhere-gp.herokuapp.com/https://api.twitter.com/1.1/trends/place.json?id=23424977";

  fetch(url, requestOptions)
    .then((response) => response.json())
    .then((responseJson) => topFive(responseJson))
    .catch((error) => console.log("error", error));
}


function topFive(responseJson) {
  for (let i = 0; i < 5; i++) {
    topics.push(responseJson[0].trends[i].name);
    getNews(responseJson[0].trends[i].name.replace("#", ""), i);
  }
}

function getTopicURL(topic) {
  return `https://api.cognitive.microsoft.com/bing/v7.0/news/search?q=${topic}&count=5`;
}

function getHeaders() {
  var headers = new Headers();
  headers.append('Ocp-Apim-Subscription-Key', '******');
  return headers;
}

function getOptions() {
  return {
    headers: getHeaders(),
    method: 'GET',
    redirect: 'follow'
  };
}

function fetchAsJSON(url, options) {
  return fetch(url, options).then(response => response.json());
}

function toThunk(fn, ...args) {
  return () => fn(...args);
}

function delay(ms, fn) {
  return new Promise((resolve, reject) => {
    setTimeout(function () { 
      fn().then(resolve).catch(reject);
    }, ms);
  });
}

function getNews(topic, index) {
  return delay(
    index * 1000,
    toThunk(
      fetchAsJSON,
      getTopicURL(topic),
      getOptions()
    )
  );
}

Promise.
  all(topics.map(getNews)).
  then(topicsArray => {
  topicsArray.forEach((topic, index) => {
      topNews[index] = topic.value;
    });
  }).
  catch(exception => {
    console.log('error:', exception);
  });

getTrends();
getNews();

console.log(topNews);
gmacerola
  • 57
  • 1
  • 7
  • Here you can find some suggestions on how to chain your promises. https://stackoverflow.com/questions/24586110/ If chaining is still to fast, you can add a delay in between. The first thing you should do is refactoring `getNews` to return the promise, so that the caller can wait for it. – kai Aug 17 '20 at 14:12

1 Answers1

0

You could use Promises and setTimeout. Below is some example code that you can try. I've added several comments as explanation.

I refactored your code from inline to separate utility functions to make it a bit more modular.

// --- FETCH UTILITY FUNCTIONS ---
function getTopicURL(topic) {
  return `https://api.cognitive.microsoft.com/bing/v7.0/news/search?q=${topic}&count=5`;
}

function getHeaders() {
  var headers = new Headers();
  headers.append('Ocp-Apim-Subscription-Key', '******');
  return headers;
}

function getOptions() {
  return {
    headers: getHeaders(),
    method: 'GET',
    redirect: 'follow'
  };
}

function fetchAsJSON(url, options) {
  return fetch(url, options).then(response => response.json());
}



// --- "LAZY" UTILITIES ---
function toThunk(fn, ...args) {
  // creates a `thunk`
  return () => fn(...args);
}

function delay(ms, fn) {
  // returns a promise that wraps a call to setTimeout. note that
  // the `fn` parameter has to be a thunk!
  return new Promise((resolve, reject) => {
    setTimeout(function () { 
      fn().then(resolve).catch(reject);
    }, ms);
  });
}



// --- PROG ---
function getNews(topic, index) {
  // grabs 5 news for 1 topic, defers fetching by 1 second per item
  // (first item = 0 ms, second item = 1000 ms, third item = 2000 ms, etc.)
  return delay(
    index * 1000,
    toThunk(
      fetchAsJSON,
      getTopicURL(topic),
      getOptions()
    )
  );
}



let topics = ['topic-a', 'topic-b', 'topic-c', 'topic-d', 'topic-e'];
Promise.
  all(topics.map(getNews)).
  then(topicsArray => {
    // when all topics return, iterate over them and store all news per topic
    topicsArray.forEach((topic, index) => {
      topNews[index] = topic.value;
    });
    checkNewsDone(); // <-- not sure if needed or not since I don't know what it does
  }).
  catch(exception => {
    console.log('error:', exception);
  });
David
  • 3,552
  • 1
  • 13
  • 24
  • Thanks, David and Kai for your help. I will attempt to look through your code and refactor mine and give it a try. This has been very helpful and educational. – gmacerola Aug 17 '20 at 17:02