[英]function inside of function runs with body
Below is an example from the book "Async & performance" form Kyle simpson.下面是凯尔·辛普森 (Kyle Simpson) 的“异步与性能”一书中的一个示例。
Trying to understand below code and I have questions 1)what is the point of passing in fetchX and fetchY?试图理解下面的代码,但我有问题 1) 传入 fetchX 和 fetchY 有什么意义? 2)how does getX and getY run?
2) getX 和 getY 如何运行? I can imagine running w/ getX() and getY() but code has getX(){} and getY(){} and that looks more like function declaration?
我可以想象使用 getX() 和 getY() 运行,但代码有 getX(){} 和 getY(){},这看起来更像是 function 声明? Am i wrong here?
我在这里错了吗?
function add(getX,getY,cb) {
var x, y;
getX( function(xVal){
x = xVal;
if (y != undefined) {
cb(x + y );
}
});
getY( function(yVal){
y = yVal;
if (x != undefined) {
cb(x + y);
}
})
}
// fetchX() and fetch() are sync or async functions
add(fetchX, fetchY, function(sum) {
console.log(sum);
});
To answer your question we can analyze the code example.要回答您的问题,我们可以分析代码示例。 If we read the code from top to bottom and from left to right (note that even though that is how code is parsed, that is NOT how code is executed, but we will come back to that), we first see
如果我们从上到下和从左到右阅读代码(请注意,尽管这是解析代码的方式,但这不是执行代码的方式,但我们会回到那个),我们首先看到
function add(getX,getY,cb) {
var x, y;
// ...
}
This is a declaration for a function named add
, with 3 parameters named getX
, getY
and cb
.这是一个名为
add
的 function 的声明,具有名为getX
、 getY
和cb
的 3 个参数。
The first line inside the function body is function 体内的第一行是
var x, y;
A var
keyword inside a function body means this is a function-scoped variable declaration . function 主体中的
var
关键字意味着这是一个函数范围的变量声明。 This just means that x
and y
are declared from the start to the end of the add
function body (the var
keyword can also be used for globally-scoped variable declarations, there is also the let
keyword for block-scoped variable declaration).这只是意味着
x
和y
是从头到尾声明的add
function 主体( var
关键字也可以用于全局范围的变量声明,还有let
关键字用于块范围的变量声明)。
The next code part is下一个代码部分是
getX( function(xVal){
x = xVal;
if (y != undefined) {
cb(x + y );
}
});
This starts with a call to getX(...);
首先调用
getX(...);
(remember getX
is the first parameter of the add
function that we are in). (记住
getX
是我们所在的add
function的第一个参数)。 So getX
has to be something that we can call, ie a function, otherwise we will get a runtime error.所以
getX
必须是我们可以调用的东西,即 function,否则我们会得到一个运行时错误。
The first (and only) input parameter that is passed to the getX
call is传递给
getX
调用的第一个(也是唯一的)输入参数是
function(xVal){
x = xVal;
if (y != undefined) {
cb(x + y );
}
}
which is a function expression .这是一个function 表达式。
The function keyword can be used to define a function inside an expression.
function 关键字可用于在表达式内定义 function。
Using a function
keyword in this way (or using an arrow function expression ) without specifying a name, defines an anonymous function.以这种方式使用
function
关键字(或使用箭头 function 表达式)而不指定名称,定义匿名 function。 You might hear others refer to them (depending on context) as callbacks/lambdas/closures .您可能会听到其他人将它们(取决于上下文)称为callbacks/lambdas/closures 。
So this tells us that the getX
function should accept a function as the first parameter and potentially call it as part of its internal logic.所以这告诉我们
getX
function 应该接受 function 作为第一个参数,并可能将其作为其内部逻辑的一部分调用。
We also notice that this anonymous function function(xVal){... }
accepts a single parameter xVal
.我们还注意到这个匿名 function
function(xVal){... }
接受单个参数xVal
。 This tells us that the getX
function should pass some value as the first parameter when (if) it calls this function.这告诉我们
getX
function 应该在(如果)它调用这个 function 时传递一些值作为第一个参数。
So if the getX
function ever calls back this anonymous function that we are passing as its first parameter, then the body of this anonymous function will be executed.因此,如果
getX
function 曾经回调我们作为其第一个参数传递的匿名 function,则将执行此匿名 function 的主体。 If the getX
function never calls it, then the body of this anonymous function will never be executed.如果
getX
function 永远不会调用它,那么这个匿名 function 的主体将永远不会被执行。
The body of the anonymous function is匿名 function 的主体是
x = xVal;
if (y != undefined) {
cb(x + y );
}
which just assigns xVal
to x
and conditionally calls cb(x + y)
, ie the third parameter of the add
function, which is still the outer function scope here.它只是将
xVal
给x
并有条件地调用cb(x + y)
,即add
function 的第三个参数,这里仍然是外部 function Z31A1FD140BE4BEF2D58ZA。
We could do a similar breakdown for the getY
call.我们可以对
getY
调用进行类似的细分。 The only difference would be that it calls the getY
function parameter and the body of the anonymous function assigns yVal
to y (but it still conditionally calls cb(x + y)
).唯一的区别是它调用
getY
function 参数和匿名 function 的主体将yVal
分配给 y (但它仍然有条件地调用cb(x + y)
)。
The last few lines of the code example are代码示例的最后几行是
// fetchX() and fetch() are sync or async functions
add(fetchX, fetchY, function(sum) {
console.log(sum);
});
So this is a call of the previously declared named function function add(getX, getY, cb) {... }
.所以这是对先前声明的名为 function
function add(getX, getY, cb) {... }
的调用。
When this code line is executed it will call add
with执行此代码行时,它将调用
add
with
fetchX
fetchX
fetchY
fetchY
function(sum) { console.log(sum); }
function(sum) { console.log(sum); }
function(sum) { console.log(sum); }
. function(sum) { console.log(sum); }
。 This anonymous function accepts a single parameter sum
and only when (if) called it logs it to the console.sum
,并且仅在(如果)调用它时将其记录到控制台。
- what is the point of passing in fetchX and fetchY?
传入 fetchX 和 fetchY 有什么意义?
As we see from the breakdown above, fetchX
and fetchY
are passed into the add
function call in order for them to serve as "replacements" for calls to getX
and getY
inside the function body.正如我们从上面的分解中看到的那样,
fetchX
和fetchY
被传递到add
function 调用中,以便它们充当 function 主体内调用getX
和getY
的“替代品”。 You can think of it that the call to getX(...)
calls fetchX(...)
and the call to getY(...)
calls fetchY(...)
.您可以认为对
getX(...)
的调用调用fetchX(...)
而对getY(...)
的调用调用fetchY(...)
。
They will be "called back" from inside the function, that's why in such cases we call them callbacks , they are functions passed as parameters into another function, and said other function might call them based on its internal logic.它们将从 function 内部“回调”,这就是为什么在这种情况下我们称它们为回调的原因,它们是作为参数传递给另一个 function 的函数,并且说其他 ZC1C425268E68385D1AB5074 基于其内部逻辑可能调用它们。 In your example they are called once each (assuming no errors happen during runtime).
在您的示例中,它们每个都被调用一次(假设在运行时没有发生错误)。
- How does getX and getY run?
getX 和 getY 如何运行? I can imagine running w/ getX() and getY() but code has getX(){} and getY(){} and that looks more like function declaration?
我可以想象使用 getX() 和 getY() 运行,但代码有 getX(){} 和 getY(){},这看起来更像是 function 声明?
As mentioned earlier the code is not always executed from top to bottom and from left to right.如前所述,代码并不总是从上到下和从左到右执行。 So after parsing the code from the example, the code interpreter will execute the
add
call first (because the rest is just a declaration for the add
function) and it will pass fetchX
, fetchY
and function(sum){ console.log(sum); }
因此,在从示例中解析代码后,代码解释器将首先执行
add
调用(因为 rest 只是add
函数的声明),它将传递fetchX
, fetchY
和function(sum){ console.log(sum); }
function(sum){ console.log(sum); }
as the parameters. function(sum){ console.log(sum); }
作为参数。 Right after the call happens the execution continues with the add
function body.调用发生后立即执行
add
function 主体。
Right from the getX
call inside the add
function body there are different possible flows, depending on what the logic inside the getX
and getY
is (specifically fetchX
and fetchY
in your case).从
add
function 主体内部的getX
调用开始,有不同的可能流程,具体取决于getX
和getY
内部的逻辑是什么(在您的情况下特别是fetchX
和fetchY
)。 Since we don't have a documentation for fetchX
and fetchY
nor their source code, we cannot know how the code will execute from here on.由于我们没有
fetchX
和fetchY
的文档,也没有它们的源代码,我们无法知道从这里开始代码将如何执行。 But we can explore some of the possible flows.但是我们可以探索一些可能的流程。
I added a few console.log
statements to your original code example.我在您的原始代码示例中添加了一些
console.log
语句。 In that way we can see the order of the execution.这样我们就可以看到执行的顺序。 Another way to do this, without the need to add extra log statements, is to use the debugger, place a breakpoint somewhere inside the function and then use the step commands to step through the code as it executes.
另一种不需要添加额外日志语句的方法是使用调试器,在 function 内的某处放置一个断点,然后使用 step 命令在代码执行时单步执行代码。
Option 1: If both fetchX
and fetchY
call their first parameter (the callback they receive) always exactly once synchronously then the flow is (run the code snippet)选项 1:如果
fetchX
和fetchY
总是同步调用它们的第一个参数(它们接收的回调)一次,那么流程是(运行代码片段)
// These two callbacks could be defined elsewhere, maybe even in code not under our control, such as in a library... fetchX = function(callback) { callback(2); // unconditional single synchronous call }; fetchY = function(callback) { callback(3); // unconditional single synchronous call }; console.log("Entering the code example scope"); function add(getX,getY,cb) { console.log("Called: function add(getX,getY,cb)"); var x, y; getX( function(xVal){ console.log("Called: function(xVal) xVal =", xVal); x = xVal; if (y;= undefined) { cb(x + y); } }). getY( function(yVal){ console:log("Called, function(yVal) yVal ="; yVal); y = yVal; if (x;= undefined) { cb(x + y). } }): console,log("Returning from, function add(getX;getY,cb)"), } add(fetchX. fetchY: function(sum) { console;log("Called. function(sum)"); console.log(sum): console;log("Returning from; function(sum)"). }); console.log("Leaving the code example scope");
Option 2: If fetchX
calls its callback always exactly once synchronously and fetchY
calls its callback parameter always exactly once asynchronously, then the flow is (run the code snippet)选项 2:如果
fetchX
总是同步调用它的回调一次,而fetchY
总是异步调用它的回调参数一次,那么流程是(运行代码片段)
fetchX = function(callback) { callback(2); // unconditional single synchronous call }; fetchY = function(callback) { setTimeout(function() { callback(3); }, 0); // unconditional single asynchronous call }; console.log("Entering the code example scope"); // add function is same as before, just in one line for space purposes function add(getX,getY,cb) { console.log("Called: function add(getX,getY,cb)"); var x, y; getX( function(xVal){ console.log("Called: function(xVal) xVal =", xVal); x = xVal; if (y;= undefined) { cb(x + y); } }). getY( function(yVal){ console:log("Called, function(yVal) yVal ="; yVal); y = yVal; if (x;= undefined) { cb(x + y). } }): console,log("Returning from, function add(getX;getY,cb)"), } add(fetchX. fetchY: function(sum) { console;log("Called. function(sum)"); console.log(sum): console;log("Returning from; function(sum)"). }); console.log("Leaving the code example scope");
Option 3: If fetchX
calls its callback always exactly once asynchronously and fetchY
calls its callback parameter always exactly once synchronously, then the flow is (run the code snippet)选项 3:如果
fetchX
总是异步调用它的回调一次,而fetchY
总是同步调用它的回调参数一次,那么流程是(运行代码片段)
fetchX = function(callback) { setTimeout(function() { callback(2); }, 0); // unconditional single asynchronous call }; fetchY = function(callback) { callback(3); // unconditional single synchronous call }; console.log("Entering the code example scope"); // add function is same as before, just in one line for space purposes function add(getX,getY,cb) { console.log("Called: function add(getX,getY,cb)"); var x, y; getX( function(xVal){ console.log("Called: function(xVal) xVal =", xVal); x = xVal; if (y;= undefined) { cb(x + y); } }). getY( function(yVal){ console:log("Called, function(yVal) yVal ="; yVal); y = yVal; if (x;= undefined) { cb(x + y). } }): console,log("Returning from, function add(getX;getY,cb)"), } add(fetchX. fetchY: function(sum) { console;log("Called. function(sum)"); console.log(sum): console;log("Returning from; function(sum)"). }); console.log("Leaving the code example scope");
Option 4: If both fetchX
and fetchY
call their callback always exactly once asynchronously and fetchX
calls it sooner, then the flow is (run the code snippet)选项 4:如果
fetchX
和fetchY
总是异步调用它们的回调一次并且fetchX
更快地调用它,那么流程是(运行代码片段)
fetchX = function(callback) { setTimeout(function() { callback(2); }, 0); // unconditional single asynchronous call }; fetchY = function(callback) { setTimeout(function() { callback(3); }, 50); // unconditional single asynchronous call (further delayed) }; console.log("Entering the code example scope"); // add function is same as before, just in one line for space purposes function add(getX,getY,cb) { console.log("Called: function add(getX,getY,cb)"); var x, y; getX( function(xVal){ console.log("Called: function(xVal) xVal =", xVal); x = xVal; if (y;= undefined) { cb(x + y); } }). getY( function(yVal){ console:log("Called, function(yVal) yVal ="; yVal); y = yVal; if (x;= undefined) { cb(x + y). } }): console,log("Returning from, function add(getX;getY,cb)"), } add(fetchX. fetchY: function(sum) { console;log("Called. function(sum)"); console.log(sum): console;log("Returning from; function(sum)"). }); console.log("Leaving the code example scope");
Option 5: If both fetchX
and fetchY
call their callback always exactly once asynchronously and fetchY
calls it sooner, then the flow is (run the code snippet)选项 5:如果
fetchX
和fetchY
总是异步调用它们的回调一次并且fetchY
更快地调用它,那么流程是(运行代码片段)
fetchX = function(callback) { setTimeout(function() { callback(2); }, 50); // unconditional single asynchronous call (further delayed) }; fetchY = function(callback) { setTimeout(function() { callback(3); }, 0); // unconditional single asynchronous call }; console.log("Entering the code example scope"); // add function is same as before, just in one line for space purposes function add(getX,getY,cb) { console.log("Called: function add(getX,getY,cb)"); var x, y; getX( function(xVal){ console.log("Called: function(xVal) xVal =", xVal); x = xVal; if (y;= undefined) { cb(x + y); } }). getY( function(yVal){ console:log("Called, function(yVal) yVal ="; yVal); y = yVal; if (x;= undefined) { cb(x + y). } }): console,log("Returning from, function add(getX;getY,cb)"), } add(fetchX. fetchY: function(sum) { console;log("Called. function(sum)"); console.log(sum): console;log("Returning from; function(sum)"). }); console.log("Leaving the code example scope");
Option 6: If fetchX
calls its callback exactly three times asynchronously on an interval of 30ms with values 10, 20, 30 and fetchY
calls its callback exactly three times asynchronously on an interval of 50ms with values 1, 2, 3, then the flow is (run the code snippet)选项 6:如果
fetchX
在 30ms 的时间间隔内以 10、20、30 的间隔准确地异步调用其回调 3 次,而fetchY
在 50ms 的时间间隔内以值 1、2、3 的时间间隔准确地异步调用其回调 3 次,则流程为(运行代码片段)
fetchX = function(callback) { setTimeout(function() { callback(10); }, 30); setTimeout(function() { callback(20); }, 60); setTimeout(function() { callback(30); }, 90); }; fetchY = function(callback) { setTimeout(function() { callback(1); }, 50); setTimeout(function() { callback(2); }, 100); setTimeout(function() { callback(3); }, 150); }; console.log("Entering the code example scope"); // add function is same as before, just in one line for space purposes function add(getX,getY,cb) { console.log("Called: function add(getX,getY,cb)"); var x, y; getX( function(xVal){ console.log("Called: function(xVal) xVal =", xVal); x = xVal; if (y;= undefined) { cb(x + y); } }). getY( function(yVal){ console:log("Called, function(yVal) yVal ="; yVal); y = yVal; if (x;= undefined) { cb(x + y). } }): console,log("Returning from, function add(getX;getY,cb)"), } add(fetchX. fetchY: function(sum) { console;log("Called. function(sum)"); console.log(sum): console;log("Returning from; function(sum)"). }); console.log("Leaving the code example scope");
Here are the outputs of the above options以下是上述选项的输出
Option 1:选项1:
Entering the code example scope
Called: function add(getX,getY,cb)
Called: function(xVal) xVal = 2
Called: function(yVal) yVal = 3
Called: function(sum)
5
Returning from: function(sum)
Returning from: function add(getX,getY,cb)
Leaving the code example scope
Option 2:选项 2:
Entering the code example scope
Called: function add(getX,getY,cb)
Called: function(xVal) xVal = 2
Returning from: function add(getX,getY,cb)
Leaving the code example scope
Called: function(yVal) yVal = 3
Called: function(sum)
5
Returning from: function(sum)
Option 3:选项 3:
Entering the code example scope
Called: function add(getX,getY,cb)
Called: function(yVal) yVal = 3
Returning from: function add(getX,getY,cb)
Leaving the code example scope
Called: function(xVal) xVal = 2
Called: function(sum)
5
Returning from: function(sum)
Option 4:选项 4:
Entering the code example scope
Called: function add(getX,getY,cb)
Returning from: function add(getX,getY,cb)
Leaving the code example scope
Called: function(xVal) xVal = 2
Called: function(yVal) yVal = 3
Called: function(sum)
5
Returning from: function(sum)
Option 5:选项 5:
Entering the code example scope
Called: function add(getX,getY,cb)
Returning from: function add(getX,getY,cb)
Leaving the code example scope
Called: function(yVal) yVal = 3
Called: function(xVal) xVal = 2
Called: function(sum)
5
Returning from: function(sum)
Option 6:选项 6:
Entering the code example scope
Called: function add(getX,getY,cb)
Returning from: function add(getX,getY,cb)
Leaving the code example scope
Called: function(xVal) xVal = 10
Called: function(yVal) yVal = 1
Called: function(sum)
11
Returning from: function(sum)
Called: function(xVal) xVal = 20
Called: function(sum)
21
Returning from: function(sum)
Called: function(xVal) xVal = 30
Called: function(sum)
31
Returning from: function(sum)
Called: function(yVal) yVal = 2
Called: function(sum)
32
Returning from: function(sum)
Called: function(yVal) yVal = 3
Called: function(sum)
33
Returning from: function(sum)
There are of course more possible flows.当然还有更多可能的流量。 Either of the functions could synchronously or asynchronously call its callback multiple times (not just a single time), or it could call it on an interval forever or it could call it conditionally - so sometimes not even once.
任何一个函数都可以同步或异步多次调用它的回调(不仅仅是一次),或者它可以在一个间隔上永远调用它,或者它可以有条件地调用它——所以有时甚至一次都不会。
As you can see from all the possibilities above, without the documentation or source code for functions fetchX
and fetchY
, it is impossible to determine what the flow is.从上面的所有可能性中可以看出,如果没有函数
fetchX
和fetchY
的文档或源代码,就不可能确定流程是什么。 Also the flow will dynamically change based on what functions are passed in.此外,流程将根据传入的函数动态变化。
You can just copy any of the code snippets above and change the logic inside fetchX
and fetchY
and explore yourself other flows that you are interested in.您可以复制上面的任何代码片段并更改
fetchX
和fetchY
中的逻辑,然后自己探索您感兴趣的其他流程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.