0

I have a recursive function that loops over elements, i want to console log the json object once the recursive function has completed. would this be best with a promise or callback?

here is my current code

function productData(elem) {
    if(elem.hasAttribute("itemprop")) {
      const itemProp =  elem.getAttribute("itemprop");
      const itemText = elem.innerText;
      items[itemProp] = itemText;
      console.log("items", items);
    }

    if (elem.hasChildNodes()) {
      Array.from(elem.children).forEach(function (item) {
        productData(item);
      });
    }
  }

  const items = {}
  // Get All Products on the page
  const product = document.querySelectorAll('[itemtype="http://schema.org/Product"]');

  productData(product[0])
Adam
  • 1,136
  • 8
  • 26
  • 51
  • 4
    You aren't doing anything asynchronous that would require using a promise. Just log it – charlietfl Apr 09 '19 at 20:26
  • @charlietfl Can you show me with an example in your answer? – Adam Apr 09 '19 at 20:29
  • Expanding on @charlietfl's comment, promises are intended for non-[CPU-bound](https://stackoverflow.com/questions/868568/what-do-the-terms-cpu-bound-and-i-o-bound-mean) processes, e.g. networking, I/O, waiting for user input. Everything you're doing in this function is CPU bound so turning it into a promise won't actually bring any benefit in terms of performance. – p.s.w.g Apr 09 '19 at 20:32
  • Just call your function and right after it log the object – charlietfl Apr 09 '19 at 20:33

2 Answers2

0

You are not doing anything asynchronous, you need neither callbacks nor promises. Just synchronously return a value.

In your current code, all you need to do is console.log(item) after the call.

A better approach would be to create the object inside the function and return it, though:

function productData(elem, items={}) {
  if (elem.hasAttribute("itemprop")) {
    const itemProp = elem.getAttribute("itemprop");
    const itemText = elem.textContent;
    items[itemProp] = itemText;
  }

  for (const child of elem.children) {
    productData(child, items);
  }
  return items;
//^^^^^^
}

// Get All Products on the page
const productItems = productData(document.querySelector('[itemtype="http://schema.org/Product"]'));
console.log(productItems);
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I don't this would work? (I'm respecting the 381k rep here) Isn't `items` a hash that's being modified? Its updated values won't be passed in the `for` loop. – Joseph Cho Apr 09 '19 at 20:40
  • @JosephCho A mutable object, yes. The values from all the (recursive) calls are added to the same object, which is returned in the end. (Admittedly, that's not as clean as it could be. Doing `const items = {}; … Object.assign(items, productData(child)); … return items;` might be better). – Bergi Apr 09 '19 at 20:43
0

As mentioned earlier, you don't need a promise for this particular case. You could wrap your item in a closure and pass it back once your recursion is complete.

function callProductData(product, output) {

  function productData(elem, items) {
    if (elem.hasAttribute("itemprop")) {
      const itemProp =  elem.getAttribute("itemprop");
      const itemText = elem.innerText;
      items[itemProp] = itemText;
    }

    if (elem.hasChildNodes()) {
      Array.from(elem.children).forEach(function (item) {
        productData(item);
      });
    }
  }

  productData(product, output);
  console.log(output);
}

var product = document.querySelectorAll('[itemtype="http://schema.org/Product"]'[0];
callProductData(product, {});
Joseph Cho
  • 4,033
  • 4
  • 26
  • 33