1

I've made a chrome extension which fetches prices from a JSON document and inserts them into the website but the prices are being inserted in the wrong order. The website is csgoempire.com/withdraw

I've tried setting up a timeout for the chrome.runtime.sendMessage but that only delayed it in the beginning, not for every loop-run.

content.js

function replacePrices() {
    let skinNumber = 1;
    console.log("Changing Prices");
    let prices = document.getElementsByClassName('item__price');

    var priceNumber = 0;
    for (elt of prices) {
        var skinNick = document.getElementsByClassName("px-2");
        let skinFullName = skinNick[skinNumber].textContent;

        let containsFactoryNew = skinFullName.includes('Factory New');
        let containsMinimalWear = skinFullName.includes('Minimal Wear');
        let containsFieldTested = skinFullName.includes('Field-Tested');
        let containsWellWorn = skinFullName.includes('Well-Worn');
        let containsBattleScarred = skinFullName.includes('Battle-Scarred');

        let isBundle = skinFullName.includes('Bundle');

        if (isBundle === true) {
            let price = 'Bundle';
        } else {

            if (containsFactoryNew === true || containsMinimalWear === true || containsFieldTested === true || containsWellWorn === true || containsBattleScarred === true) {
                skinWear = '(' + skinFullName + ')';
                skinFullName = '';
            } else {
                skinFullName = skinFullName.trim();
                skinFullName = skinFullName.replace(/\s\s+/g, ' | ');
                skinFullName = skinFullName + ' ' + skinWear;
                console.log(skinFullName);

                chrome.runtime.sendMessage(
                    {contentScriptQuery: "queryPrice", itemURL: skinFullName},
                    price => {
                        prices[priceNumber].innerHTML = prices[priceNumber].innerHTML + ' | ' + price;
                        prices[priceNumber].style.cssText = 'color: silver; font-size: .8125rem; font-weight: 700; font-family: Lato,sans-serif;';
                        priceNumber = priceNumber + 1;
                    });
                skinWear = '';
            }
        }

        // http://steamcommunity.com/market/priceoverview/?appid=730&currency=3&market_hash_name=StatTrak%E2%84%A2 M4A1-S | Hyper Beast (Minimal Wear)

        skinNumber = skinNumber + 1;
    }

    btnReplace.innerHTML = "Reload Steam Market Prices";
}


background.js

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
      if (request.contentScriptQuery == "queryPrice") {
        var url = "https://pixelboii.wtf/steamvalue.json";
        var skinFullName = request.itemURL;
        fetch(url)
            .then(res => res.json())
            .then(price => {
              sendResponse(price.items_list[skinFullName].price["7_days"].average);
            })
            .catch(err => { throw err });
        return true;  // Will respond asynchronously.
      }
    });

The prices are supposed to load so that they match up with the item they are placed below, but currently, they get mixed up with each other. No error codes.

PixelBoii
  • 21
  • 2
  • 6
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – wOxxOm Oct 30 '19 at 12:35

1 Answers1

0

The problem you have is a classic issue of parallel access to a variable. Essentially, what happens is that your priceNumber gets incremented by 1 every time you fetch a price, but it's possible that 2 price fetches return at the same time, update the DOM at the same time and then increment at the same time, but they're using the same priceNumber value to determine where to insert their price.

The easiest way to solve this is by also returning the skinFullName alongside your price, and then having a Map between the skinFullName and the index. That way you can look up a fixed index based on the skinFullName and don't need to rely on the skin price fetches arriving in the same order as you fetch them (which in this case also isn't guaranteed).

Nzall
  • 3,439
  • 5
  • 29
  • 59