I have a formidable form which parse the request. Then along with this request is the file being uploaded.. In formidable you can listen to an event if there's a file.
var form = new formidable.IncomingForm({
uploadDir: __dirname + '/temp',
keepExtensions: true
});
This is where I will listen to the event
form.on('file', function(name, file){
var file = file;
fs.readFile(file.path, readFileCallback);
});
function readFileCallback(err, contents){
console.log(file);
if (err) throw err;
....
}
My first code was a chain of callback functions and it's kind of hard to read and maintain so I switch with this approach where I would declare functions then call it as a callback instead of like this:
form.on('file', function(name, file){
fs.readFile(file.path, function(err, contents){
console.log(file);
if (err) throw err;
....
});
});
With this kind of approach, I could access the outside variable which is file
. I'm wondering what is the difference between the two in accessing the outside variables. Thanks in advance.
It's a matter of scope . Code has access to the variables declared within the function, its containing function (if any), its containing function (if any), and so on, and then globals.
In your first example, readFileCallback
is declared outside the form.on
callback, and so it doesn't have access to things inside the form.on
callback.
In your second example, the function is inside the form.on
callback, and so it does have access to the things inside it.
Note that in the second example, in theory a new function is created each time the callback is called. That's fine, JavaScript engines are really fast at creating functions (and good ones will reuse the code even though a separate function object is created).
Normally you want to create the function at the outermost location where it has access to everything it needs. So in your case, that would be inside form.on
, but outside the readFile
callback. Which is exactly where your second example has it. But you can use a named function like your first example if you like, just put it in form.on
's callback:
form.on('file', function(name, file){
fs.readFile(file.path, readFileCallback);
function readFileCallback(err, contents){
console.log(file);
if (err) throw err;
....
}
});
Let's take an example where everything had a simple name, and follow through two calls:
function outer(outerArg) {
function middle(middleArg) {
function inner(innerArg) {
console.log("innerArg = " + innerArg);
console.log("middleArg = " + middleArg);
console.log("outerArg = " + outerArg);
}
inner(middleArg.toLowerCase());
}
middle(outerArg.toUpperCase());
}
outer
contains middle
which contains inner
, and outer
calls middle
(and middle
calls inner
). A call:
outer("Test1");
outer
gets the arg "Test1"
middle
with "TEST1"
inner
with "test1"
inner
outputs:
\ninnerArg = test1 \nmiddleArg = TEST1 \nouterArg = Test1 \n
So far, so simple, but it's more exciting than that: What if middle
returns a function that calls inner
, instead of calling it immediately, and outer
returns returns middle
's return value?
function outer(outerArg) {
function middle(middleArg) {
function inner(innerArg) {
console.log("innerArg = " + innerArg);
console.log("middleArg = " + middleArg);
console.log("outerArg = " + outerArg);
}
function caller() { // ***
inner(middleArg.toLowerCase()); // ***
} // ***
return caller; // ***
}
return middle(outerArg.toUpperCase()); // ***
}
Now, calling outer
doesn't have any output at all:
var f = outer("Test2");
But then calling the function middle
returned ( caller
) does:
f();
Output:
innerArg = test2 middleArg = TEST2 outerArg = Test2
The arguments still exist after outer
and middle
return! But it's even more interesting:
var f1 = outer("Test3");
var f2 = outer("Test4");
f2(); // Note -- calling the second one first
f1();
Output:
innerArg = test4 middleArg = TEST4 outerArg = Test4 innerArg = test3 middleArg = TEST3 outerArg = Test3
So that means, two outerArg
s still existed after both calls to outer
had finished, along with two middleArgs
. How?
They exist on objects attached to the functions:
outer
creates an execution context (an object), which amongst other things (and leaving out a lot of details) holds the arguments and local variables for that call to outer
. Let's call it the "outer context." It also has a reference to the execution context containing it (the global context, in our code). Normally that object gets cleaned up when a functon returns... outer
creates a function, middle
. When you create a function, the current execution context is attached to the function. That's how it has access to the variables and such in that outer context. outer
calls middle
, creating an inner execution context, and middle
creates two other function ( inner
and caller
), which each get that inner context attached to them. middle
then returns caller
, so caller
exists after the call to middle
completes. Since caller
has a reference to the inner execution context, the context continues to exist (just like any other object), even though middle
has returned. Since that context has a reference to inner
, inner
also continues to exist. outer
returns the return value of middle
(which is caller
), and so that means caller
still exists when outer
returns, which means the inner context it refers to still exists, which means inner
still exists, and the outer context still exists because the inner context has a reference to it. ...which is how f1
and f2
have access to those arguments after outer
returns: When you run them, they look up the values in the contexts attached to them.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.