How do you set data in a function and keep it that way outside the function?

Currently, I have a while loop that uploads files to cloudinary. Cloudinary gives you the data in a function. I want replace the value of each local file with the URL which that can be done inside the function. But when you try to access the same data outside the function, it is still the old value (e.g. kitten-playing.gif instead of https://res.cloudinary.com/aboutdavid/image/upload/v1605242001/samples/animals/kitten-playing.gif). So, how can you set data in a function and keep it that way outside the function?

const cheerio = require("cheerio");
const fs = require("fs");
const cloudinary = require("cloudinary").v2;

const $ = cheerio.load(
  '<img src="kitten-playing.gif"><img src="accessories-bag.jpg"><img src="sample.jpg">'
);

for (let i = 0; i <  $("img").length; i++) {
  if (fs.existsSync($("img")[i].attribs.src)) {
    cloudinary.uploader.upload($("img")[i].attribs.src, function(
      error,
      result
    ) {
      $("img")[i].attribs.src = result.url;
      console.log(`In function (${i}): ${$("img")[i].attribs.src}`)
// https://res.cloudinary.com/aboutdavid/image/upload/v1605242001/samples/animals/kitten-playing.gif
    });
    console.log(`Out function (${i}): ${$("img")[i].attribs.src}`)
// kitten-playing.gif
  }
}

Edit: That’s really all it is supposed to do, change the src local paths to URLs

1 Like

I sometimes throw a variable outside the function and use that

I’ve got a feeling this is just a callback order-of-operations thing.

Look at your DevTools Console. I suspect you’ll see them paired like Out... In instead of In...Out because the ‘Out’ log line runs first, so your code is doing what you want, but the logs are tricking you.

Callbacks happen when they happen. You can’t read down through the code file and assume that’s the order of execution :slight_smile:

Use the DevTools element inspector to check the src of the images after the function runs. Or make a button that prints out all of the img srcs at a time of your choosing.

2 Likes

Oh, I forgot t mention this is Node.js and Cheerio. I honestly this using the document function would be a lot easier but I can’t

But yes,

that is right:

Out function (0): kitten-playing.gif
Out function (1): accessories-bag.jpg
Out function (2): sample.jpg
In function (2): http://res.cloudinary.com/aboutdavid/image/upload/v1605274932/rjhutiwjlupqkpcuw5rw.jpg
In function (1): http://res.cloudinary.com/aboutdavid/image/upload/v1605274932/m2eaf5f2ayynqc5xpjfv.jpg
In function (0): http://res.cloudinary.com/aboutdavid/image/upload/v1605274932/oqdompfkgxao7wnlnbal.gif
1 Like

Also, yeah, that does not work really:

const cheerio = require("cheerio");
const fs = require("fs");
const cloudinary = require("cloudinary").v2;

const $ = cheerio.load(
  '<img src="kitten-playing.gif"><img src="accessories-bag.jpg"><img src="sample.jpg">'
);

var imageurl = ""
for (let i = 0; i <  $("img").length; i++) {
  if (fs.existsSync($("img")[i].attribs.src)) {
    cloudinary.uploader.upload($("img")[i].attribs.src, function(
      error,
      result
    ) {
      imageurl = result.url // URL
    });
    $("img")[i].attribs.src = imageurl // ""
  }
}

I think SteGriff is right, but I really don’t know a Node.js Solution.

Ok, so reading between the lines, your problem is that all of this happens in a server route handler, and the response going back to the client still has the original URLs?

If that’s the case, it would be good to see more of the code to advise you on the architecture.

But, broadly, you have two readily available choices:

  1. Do the response.send from within the cloudinary callback

  2. Add an argument to the function you posted above which is itself a callback, and execute that within the cloudinary callback.

I’ve expanded on the second idea more with the last guy who found themselves in callback hell

…and you should read the link above anyway, just for the learnins :cowboy_hat_face:

GLHF

3 Likes

This is a big question on stackoverflow. It’s the 9th highest voted question in the javascript tag.

Anyway, they have some detailed explanation there too, with some advice for how to rework the code to use async/await.

3 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.