简体   繁体   English

function 内部 function 与主体一起运行

[英]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 的声明,具有名为getXgetYcb的 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).这只是意味着xy是从头到尾声明的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.它只是将xValx并有条件地调用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

  • 1st parameter: fetchX第一个参数: fetchX
  • 2nd parameter: fetchY第二个参数: fetchY
  • 3rd parameter: an anonymous function function(sum) { console.log(sum); }第三个参数:匿名 function 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.这个匿名的 function 接受单个参数sum ,并且仅在(如果)调用它时将其记录到控制台。

  1. 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.正如我们从上面的分解中看到的那样, fetchXfetchY被传递到add function 调用中,以便它们充当 function 主体内调用getXgetY的“替代品”。 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).在您的示例中,它们每个都被调用一次(假设在运行时没有发生错误)。


  1. 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函数的声明),它将传递fetchXfetchYfunction(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调用开始,有不同的可能流程,具体取决于getXgetY内部的逻辑是什么(在您的情况下特别是fetchXfetchY )。 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.由于我们没有fetchXfetchY的文档,也没有它们的源代码,我们无法知道从这里开始代码将如何执行 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:如果fetchXfetchY总是同步调用它们的第一个参数(它们接收的回调)一次,那么流程是(运行代码片段)

 // 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:如果fetchXfetchY总是异步调用它们的回调一次并且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:如果fetchXfetchY总是异步调用它们的回调一次并且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.从上面的所有可能性中可以看出,如果没有函数fetchXfetchY的文档或源代码,就不可能确定流程是什么。 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.您可以复制上面的任何代码片段并更改fetchXfetchY中的逻辑,然后自己探索您感兴趣的其他流程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM