- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在 learnyounode 的帮助下学习 Nodejs,但我陷入了杂耍异步。我的解决方案除了问题中最困难的部分外都有效 - 它打印的结果不按顺序排列,因为某些请求先于其他请求完成。我试图在不使用任何辅助库的情况下做到这一点,所以我点击了谷歌。我发现了一个关于控制流的很棒的教程 - http://book.mixu.net/node/ch7.html但发现他的 Series 解决方案 - 异步 for 循环只能正常工作,因为他的异步函数在返回之前正好等待 1000 毫秒。在我的示例中,时间是可变的,因此您不会以相同的顺序获得结果。然后,该示例将构建一个控制流库,我觉得虽然这可行,但它超出了 learnyounode 分配的范围。
我尝试过的一些事情是:
创建一个包含 URL、订单和响应数据的对象。我遇到的问题是,当我坐在 http.get 的回调中时,我不知道我正在获取数据的 URL。这实际上是我尝试过的大多数事情的错误,我不知道如何将我得到的数据链接到回调中的特定 URL。
具体以asyncCounter为索引,将返回的数据放在存储数组中。因此,当事件“结束”发生时,我会将其设置为您在下面的代码中看到的那样。显然这是行不通的,因为调用是在不同的时间完成的。
最终我屈服并查看了解决方案。这是我所拥有的,我用星号标记了我的解决方案中缺少的内容。
var http = require("http");
var storage = [];
var urlList = [];
var asyncCounter = 0;
//Store all the URL's from the command line in an array
for(var i = 2; i < process.argv.length; i++){
urlList.push(process.argv[i]);
}
//This function prints out all the data in the storage array
//The storage array contains the data received from http.get
function AsyncComplete(){
for(var j = 0; j < storage.length; j++){
console.log(storage[j]);
};
};
//Entry function
function main(){
//Do an http get on each of the provided URL's
for(var i = 0; i < urlList.length; i++){
**(function(i){**
http.get(urlList[i], function(response){
var body = "";
//Got a chunk of data!
response.on("data", function(chunk){
body += chunk;
});
//All done with our request.
response.on("end", function (){
//Store the total response from the URL
storage[**i**] = body;
asyncCounter++;
//Check if we can print the results yet
//I want to wait for all the calls to complete so I am using a counter
if(asyncCounter == urlList.length){
AsyncComplete();
}
});
});
**})(i);**
};
};
main();
所以我再次点击谷歌,因为我不知道他们在做什么,我发现了一种叫做闭包的东西。根据我的理解,他们所做的让我处于回调的范围内 - 我不知道如何做到这一点,认为这是不可能的并很早就放弃了。
我的问题是它到底是如何运作的 - 特别是为什么他们有(i)他们在哪里做以及它的目的是什么。如果没有 (i),该解决方案就无法工作。为什么你可以把 (function(i){ 扔到某个地方?这是我在一百万年内从未想过要做的事情。
我找到了https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures这似乎包含答案,所以我将同时阅读它,看看我是否能想出一些东西。
预先感谢您的宝贵时间!
史蒂夫。
最佳答案
这称为立即调用函数表达式 (IIFE),只是一个立即调用的匿名函数。传递给此 IIFE 的参数 i 被放置在调用堆栈上,并且与 for 循环的外部 i 不同。你可以想象它就像创建当前 i 的快照。
在 JavaScript 中,用“var”声明的变量是函数作用域的。因此,所有回调都会访问相同的 i (这不是您想要的)。通过将其传递给 IIFE(它是一个函数,因此为变量 i 引入了自己的作用域),将为每个回调创建一个新变量。如果为 IIFE 的参数指定另一个名称,情况会变得更加明显。例如:
(function(savedI) {
// ...
})(i)
通过命名参数i,原来的i被遮蔽了。这意味着您无法访问 IIFE 内部的“外部”i。
使用 IIFE 的常见替代方法是使用map。例如:
_.range(urlList.length).map(function(i) {
// ...
})
_.range 是 underscore 中的实用函数并给出一个从 0 到 urlList.length 的数组。传递的函数将接收一个参数 i,该参数不会被覆盖(就像 for 循环在您的版本中所做的那样)。
避免该问题的另一种可能性是通过 let 声明变量,这在 EcmaScript 6 或更高版本中是可能的。这引入了 block 作用域变量。您可以阅读更多相关信息here 。例如:
for(let i = 0; i < urlList.length; i++){
// ..
}
关于javascript - 杂耍异步 - LearnYouNode - 立即调用函数表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26147077/
简而言之,这是一笔交易: http://play.golang.org/p/ePiZcFfPZP 如果我使用注释行,一切正常,但没有 对分配大小 (cap) 的任何控制,因此 slice , 如果我做
我是一名优秀的程序员,十分优秀!