1

I'm new to Javascript and am trying to get Images to dynamically add themselves to 'addCache'.

I will then use this with a service worker to add it to the cache.

My sw.js file looks like this:

    var product = [];
    fetch('http://localhost:3000/api/products')
    .then(res => res.json())
    .then(json => product = json)


//Caching Files


  var cacheName = 'pwa-v1';
  var toCache= [
      '/PW1/',
      '/PW1/Apps/calculate.js',
      '/PW1/Apps/login.js',
      '/PW1/Apps/index.js',
      '/PW1/index.html',
      '/PW1/products.html',
      '/PW1/style.css',

];


var productImages = [];

for(var i=0;i<product.length;i++){
    productImages.push('/PW1/img/'+product[i].name+'.jpg');
}
  var addCache = toCache.concat(productImages);

self.addEventListener('install', function(s) {

.............
.............
.............

My goal is to make the fetch request async, it fetches data from backend and stores it into the product array. I want the for loop to wait for the product, then begin the loop. How can I go about doing this?

The for loop just gets the product name, which is the same as the image name.

At the moment it doesn't add any images to add cache. But it does add the rest of the files.

Any help will be appreciated. Thanks in advance.

3
  • Just so I understand, you want to wait for the fetch request to complete before you start your for loop? Commented Jan 25, 2020 at 18:29
  • yes, i want my fetch request to complete before the for loop. so i can use the result of the fetch request in for loop. thanks Commented Jan 25, 2020 at 18:30
  • are you still having issues? Commented Jan 25, 2020 at 21:27

5 Answers 5

1

Use async/await. As a Promise it guarantees that either a response or rejection of requested data will be returned via the await keyword.

In the demo below the async function getPaths() will pass an endpoint (ie url of JSON) and an optional array (ie cached paths). It returns an array of all given paths. The endpoint is that of a live test server so you should have no problem testing it with your own endpoint. If you do...well you should seriously look into your back-end or Service Worker.

Demo

let toCache = [
  '/PW1/',
  '/PW1/Apps/calculate.js',
  '/PW1/Apps/login.js',
  '/PW1/Apps/index.js',
  '/PW1/index.html',
  '/PW1/products.html',
  '/PW1/style.css'
];

const getPaths = async(endpoint, cache = []) => {
  const response = await fetch(endpoint);
  let data = await response.json();

  data = cache.concat(data.map(product => `/PW1/img/${product.username}.jpg`));
  return data;
}

getPaths('https://jsonplaceholder.typicode.com/users', toCache).then(data => console.log(data));

Sign up to request clarification or add additional context in comments.

Comments

1

Because it's the function asynchronous fetch(), so you must put the code of treatment of response datas in function then()

var products = [];
fetch('http://localhost:3000/api/products')
    .then(res => res.json())
    .then(json => products = json)
    .then(() => {
       // ... treatement of product datas ...
       for(var i=0;i<products.length;i++){
         productImages.push('/PW1/img/'+products[i].name+'.jpg');
       }
     })
   .catch((e) => {
       console.log('Error', e);
    });

With the syntax ES6 JavaScript, I recommend you to use the sugar syntax "async-await" for the asynchronous code in JS. It helps you write the asynchronous code like synchronous code. And for sure, the synchronous code is much easier to understand. You should check the detail of my respone in another famous topic in StackOverFlow : How do I return the response from an asynchronous call?

Comments

1

fetch is asynchronous, so you need to create a callback that will run by calling then and do all the work that relies on the response that you get from calling your API:

// ...

var cacheName = "pwa-v1"
var toCache = ["/PW1/", "/PW1/Apps/calculate.js", ...]

fetch("http://localhost:3000/api/products")
  .then(res => res.json())
  .then(createFileCache)
  .catch(handleError)

function createFileCache(items) {
  var productImages = items.map(
    function(item) {
      return `/PW1/img/${item.name}.jpg`
    }
  )
  toCache.concat(productImages)
}

function handleError(err) {
  // handle errors appropriately
}

// ...

Keep in mind this is asynchronous, so if you need to rely on the new state of toCache somewhere else, then you might want to throw in another callback into the mix.

Comments

0
const toCache= [
      '/PW1/',
      '/PW1/Apps/calculate.js',
      '/PW1/Apps/login.js',
      '/PW1/Apps/index.js',
      '/PW1/index.html',
      '/PW1/products.html',
      '/PW1/style.css',
];
const productImages = [];
fetch('http://localhost:3000/api/products')
    .then(res => res.json())
    .then(products => {
        for (const product of products) {
            productImages.push('/PW1/img/' + product.name + '.jpg');
        }
        let addCache = toCache.concat(productImages);
        // your logic can continue here
    });

Try not to use var, let is better and in your case const is even better since it's more restrictive

Comments

0

You need to put your for loop in a function as an argument to the .then method of the Promise fetch returns, just like your json conversion function

Something like:

var product = [];
var productImages = [];


fetch('http://localhost:3000/api/products')
.then(res => res.json())
.then(json => product = json)
.then(
   function() 
   {
         for(var i=0;i<product.length;i++)
         {
            productImages.push('/PW1/img/'+product[i].name+'.jpg');
         }         
   }
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.