1

I came across this piece of code in using Dropzone JS and 3 arguments are repeated after the function body.

// Mock the file upload progress (only for the demo)
//
Dropzone.prototype.uploadFiles = function(files) {
    var minSteps         = 6;
    var maxSteps         = 60;
    var timeBetweenSteps = 100;
    var bytesPerStep     = 100000;
    var isUploadSuccess  = Math.round(Math.random());

    var self = this;

    for (var i = 0; i < files.length; i++) {

        var file = files[i];
        var totalSteps = Math.round(Math.min(maxSteps, Math.max(minSteps, file.size / bytesPerStep)));

        for (var step = 0; step < totalSteps; step++) {
            var duration = timeBetweenSteps * (step + 1);

            setTimeout(function(file, totalSteps, step) {
                return function() {
                    file.upload = {
                        progress: 100 * (step + 1) / totalSteps,
                        total: file.size,
                        bytesSent: (step + 1) * file.size / totalSteps
                    };

                    self.emit('uploadprogress', file, file.upload.progress, file.upload.bytesSent);
                    if (file.upload.progress == 100) {

                        if (isUploadSuccess) {
                            file.status =  Dropzone.SUCCESS;
                            self.emit('success', file, 'success', null);
                        } else {
                            file.status =  Dropzone.ERROR;
                            self.emit('error', file, 'Some upload error', null);
                        }

                        self.emit('complete', file);
                        self.processQueue();
                    }
                };
            }(file, totalSteps, step), duration);
        }
    }
};

At the end of the body, after the closing brace of the closure function(file, totalSteps, step) there is an additional list of arguments (file, totalSteps, step). I can't recall seeing this before so I'd like to know how they are used.

SagunKho
  • 985
  • 10
  • 26
  • 1
    It's a function call. `var foo = function(x) {console.log(x)}; foo(42);` and `function(x) {console.log(x);}(42)` (in an expression context) are the same thing. – Felix Kling Jul 07 '18 at 06:00
  • Ah right it returns a function, blind me. – SagunKho Jul 07 '18 at 06:02
  • 1
    Right, that's the function that is actually passed to `setTimeout`. – Felix Kling Jul 07 '18 at 06:03
  • Possible duplicate of [How can I pass a parameter to a setTimeout() callback?](https://stackoverflow.com/questions/1190642/how-can-i-pass-a-parameter-to-a-settimeout-callback) – Dexygen Jul 07 '18 at 06:08

6 Answers6

1

The values passed will be set to the setTimeout function's argument

For example

setTimeout(function(a, b, c) {
  console.log(a, b, c)
}(1, 2, 'hello'), 5000)
brk
  • 48,835
  • 10
  • 56
  • 78
1

Its using closure: When you are writing reusable code or any library, and you don't want to mess up with outer or global variables, you pass those variables as arguments.

In this example, you are passing global variable as g and you are free to use global as variable name.

var global = "global";
(function (g){
var global = "local";
 console.log("I am not overriden :" + g);
 console.log("I am new incarnation :" + global);
})(global);
Anupam Singh
  • 1,158
  • 13
  • 25
1

Let's say you have this function foo:

function foo(file, totalSteps, step) {
    console.log(file, totalSteps, step);
};

And here's the function call:

foo(file, totalSteps, step);

But then, you decide to call it after 5000 milliseconds, use setTimeout:

setTimeout( foo(file, totalSteps, step) , 5000);

Now instead of defining the function foo outside, you decide to define it inside setTimeout by implementing anonymous-functions:

setTimeout(function(file, totalSteps, step) {
        console.log(file, totalSteps, step);
}(file, totalSteps, step) , 5000);
vignz.pie
  • 173
  • 2
  • 14
1

This is the simple explanation of your question:

What you have is a immediately-invoked function expression (IIFE). If you strip out all the arguments you're just left with this:

setTimeout(function () {
    // some code
}(),5000);

It creates an anonymous (unnamed) function that accepts three parameters:

(function (file, totalSteps, step) {
    // some code
}());

And you pass it three arguments:

(function (file, totalSteps, step) {
    // some code
} (file, totalSteps, step));
NullPointer
  • 7,094
  • 5
  • 27
  • 41
1

The function you are passing to setTimeout is actually a function expression. Popularly known as IIFE (immediately invoked function expression).

setTimeout(fn expression, duration)

IIFE:

function name(){

}(param1, param2)

Now this function name has access to param1, param2 also this will be immediately invoked as soon as it gets created.

himank
  • 439
  • 3
  • 5
0

Basically the code is calling setTimeout's function to return another function which will called just after its definition with params file, totalSteps, step and returning. Maybe the coder have thought, that his way all params are on the same line for timer configuration: (file, totalSteps, step), duration).

Coders solution is quite complex and hard to follow. I think it would be better to avoid this kind of expression to improve readability. Also code doesn't have clearTimeout handling for setTimeout, so that code can cause problems in some environments. :)

Ville Venäläinen
  • 2,444
  • 1
  • 15
  • 11