I have a small html file for personal use, with no css or php or web server. I have a folder 'imgs' (in the same folder as the .html) that contains images called image0.png, image1.png, image2.png... (all in sequence, until there is none). How could I make a javascript function that returns the number of images in that folder ?
2 Answers
There isn't a way to immediately get the number of image files using client-side JavaScript, the best you could do is to try retrieving the images one by one until, you get a 404 error.
You can use the onerror
method of an img element to detect when a requested image doesn't exist - this method will be called if you request an image that isn't there.
This question might be useful, it contains some example code which you could use.
-
404 error ? I said no web server, no http request, no nothing. The setup could hardly be simpler, I'm the client and the server (well, not even the server actually, there's just a client). I think the idea is indeed to try to get the images until it fails, but I don't know how to do that. What would the code look like ? – NaomiJO Aug 06 '12 at 14:59
-
Your browser will still behave as though it got a 404 error, even without a web server. – apsillers Aug 06 '12 at 15:01
-
Really? That's amazing! So maybe it's the way to go, what would the function be like then ? – NaomiJO Aug 06 '12 at 15:04
-
The onerror handler will still work even for local files (no web server) – codebox Aug 06 '12 at 15:04
-
ok thanks, I'll accept the other answer because there is code that explains how to do it, but you had the same idea so I plusOned you. – NaomiJO Aug 06 '12 at 15:22
The general strategy would be to load each file as an image, in order, until a request failed, firing an onerror
callback. Each subsequent image fetch is fired as the onload
handler of the previous image.
// takes a callback that expects a single argument
function getImageCount(callback) {
imageCounter(0);
// pseduo-recursive function nested in the closure of the outer function
// (nested so `callback` is always accessible without constantly passing it)
function imageCounter(i) {
var img = new Image();
// if this failed, so the final image was the previous one
img.onerror = function() { callback(i); }
// if this succeeded, try the next one
img.onload = function() { imageCounter(i + 1); }
img.src = "image"+i+".png";
}
}
// actually run it, with callback function that gets the count
getImageCount(function(count) {
alert("There are " + count + "images.");
});
Due to restrictive same-origin policy for file:
URLs, this won't work on Chrome without the --allow-file-access-from-files
command line flag, and it will only work in Firefox if the images are being fetched from the same directory or a subdirectory of the current page.

- 112,806
- 17
- 235
- 239
-
Thanks, that seems the way to go. Is there a way to modify it to make a simple function 'reallyGetCount()' that just returns an integer that is the count of images ? I would like to wrap your code into a black box, because I'm not too familiar with callbacks. – NaomiJO Aug 06 '12 at 15:20
-
Unfortunately, in JavaScript, callbacks *are* a legitimate part of function black boxes. There's no way to load images synchronously, so there's no way to synchronously return a result from a function that depends on image loads. Callbacks are a bit difficult to use effectively at first, but they are absolutely necessary for virtually all advanced browser functionality and JS libraries. – apsillers Aug 06 '12 at 15:30
-
but could I not make yet another function that uses this callback stuff, and actually returns the value I'm interested in ?! – NaomiJO Aug 06 '12 at 15:47
-
No, you cannot. This is how it would work if you tried: 1) the black box function (BBF) starts, 2) BBF registers listener functions on image `onload` and `onerror`, 3) BBF terminates [with no return value], 4) `onload`/`onsuccess` listener functions fire. The obvious intuition is to delay termination of the BBF until after a callback fires (i.e., delay step 3 until step 4 completes). However, this is **not possible** because JS is single-threaded: the BBF needs to complete and return before any other functions (including the listener functions) can run. Thus, step 4 *must* come after step 3. – apsillers Aug 06 '12 at 15:59
-
Instead of the alert, can I do n=count, where n is a global variable ? – NaomiJO Aug 06 '12 at 16:15
-
Certainly, you can do anything you want in the callback. Just remember that the global `n` won't be set until the callback completes, so `getImageCount(function(count){ n=count; }); alert(n); doStuff(n);` will alert undefined (since the `alert` and `doStuff` run before the callback), but `getImageCount(function(count){ n=count; alert(n); doStuff(n); });` will succeed (since the `alert` and `doStuff` are in the callback). – apsillers Aug 06 '12 at 16:29
-
I'm sorry I still don't understand how it is that I can use your code into mine. I just wanted a function to tell me how many images there are in my folder... does that mean I have to place my whole code into your callback function for it to work? I don't understand why in the first case, you say the alert runs before the callback. What calls the callback, if not the getImageCount(function(count){ n=count; }); ?! – NaomiJO Aug 06 '12 at 17:03
-
*"Does that mean I have to place my whole code into your function for it to work?"* -- Yes, correct, that is exactly what you need to do. You can move your code into a function and provide that function as the callback, if you want. Regarding why the alert runs first: `getImageCount` does not run the callback; instead, it *registers the callback for later execution* by providing it as the `onerror` handler of the image. The callback can only run after the current execution flow has terminated. Callbacks cannot interrupt the execution flow; they only run when the JS thread has gone idle. – apsillers Aug 06 '12 at 17:08
-
I tried both (inside and outside of the callback, none worked). Here is my code (line 49-52): http://pastebin.com/HbALuzGE – NaomiJO Aug 07 '12 at 07:14