node js怎么判断循环结束了?

node js怎么判断循环结束了


函数式编程
浏览 1508回答 1
1回答

呼啦一阵风

Node.js&nbsp;的异步机制由事件和回调函数实现,一开始接触可能会感觉违反常规,但习惯  以后就会发现还是很简单的。然而这之中其实暗藏了不少陷阱,一个很容易遇到的问题就是  循环中的回调函数,初学者经常容易陷入这个圈套。让我们从一个例子开始说明这个问题。var&nbsp;fs = require('fs');var&nbsp;files = ['a.txt', 'b.txt', 'c.txt'];for&nbsp;(var&nbsp;i = 0; i < files.length; i++) {fs.readFile(files[i], 'utf-8',&nbsp;function&nbsp;(err, contents) {console.log(files[i] + ': ' + contents);});}这段代码的功能很直观,就是依次读取文件&nbsp;a.txt、b.txt&nbsp;、c.txt&nbsp;,并输出文件名和内容。假设这三个文件的内容分别是&nbsp;AAA&nbsp;、BBB&nbsp;和&nbsp;CCC,那么我们期望的输出结果就是:a.txt: AAAb.txt: BBBc.txt: CCC可是我们运行这段代码的结果是怎样的呢?竟然是这样的结果:undefined: AAAundefined: BBBundefined: CCC这个结果说明文件内容正确输出了,而文件名却不对,也就意味着,contents&nbsp;的结果是正确的,但&nbsp;files[i]&nbsp;的值是&nbsp;undefined。这怎么可能呢,文件名不正确却能读取文件内容?既然难以直观地理解,我们就把&nbsp;files[i]&nbsp;分解并打印出来看看,在读取文件的回调函数中分别输出&nbsp;files、i&nbsp;和&nbsp;files[i]&nbsp;。var&nbsp;fs = require('fs');var&nbsp;files = ['a.txt', 'b.txt', 'c.txt'];for&nbsp;(var&nbsp;i = 0; i < files.length; i++) {fs.readFile(files[i], 'utf-8',&nbsp;function&nbsp;(err, contents) {console.log(files);console.log(i);console.log(files[i]);});}运行修改后的代码,结果如下:[ 'a.txt', 'b.txt', 'c.txt' ]3undefined[ 'a.txt', 'b.txt', 'c.txt' ]3undefined[ 'a.txt', 'b.txt', 'c.txt' ]3undefined看到这里是不是有点启发了呢?三次输出的&nbsp;i&nbsp;的值都是&nbsp;3&nbsp;,超出了&nbsp;files&nbsp;数组的下标范围,因此&nbsp;files[i]&nbsp;的值就是&nbsp;undefined&nbsp;了。这种情况通常会在&nbsp;for&nbsp;循环结束时发生,例如&nbsp;for (var i = 0; i < files.length; i++),退出循环时&nbsp;i&nbsp;的值就files.length&nbsp;的值。既然&nbsp;i&nbsp;的值是&nbsp;3&nbsp;,那么说明了事实上&nbsp;fs.readFile&nbsp;的回调函数中访问到的&nbsp;i&nbsp;值都是循环退出以后的,因此不能分辨。而&nbsp;files[i]&nbsp;作为&nbsp;fs.readFile&nbsp;的第一个参数在循环中就传递了,所以文件可以被定位到,而且可以显示出文件的内容。现在问题就明朗了:原因是3&nbsp;次读取文件的回调函数事实上是同一个实例,其中引用到的&nbsp;i&nbsp;值是上面循环执行结束后的值,因此不能分辨。如何解决这个问题呢?我们可以利用JavaScript&nbsp;函数式编程的特性,手动建立一个闭包://forloopclosure.jsvar&nbsp;fs = require('fs');var&nbsp;files = ['a.txt', 'b.txt', 'c.txt'];for&nbsp;(var&nbsp;i = 0; i < files.length; i++) {(function&nbsp;(i) {fs.readFile(files[i], 'utf-8',&nbsp;function&nbsp;(err, contents) {console.log(files[i] + ': ' + contents);});})(i);}上面代码在&nbsp;for&nbsp;循环体中建立了一个匿名函数,将循环迭代变量&nbsp;i&nbsp;作为函数的参数传递并调用。由于运行时闭包的存在,该匿名函数中定义的变量(包括参数表)在它内部的函数(fs.readFile&nbsp;的回调函数)执行完毕之前都不会释放,因此我们在其中访问到的&nbsp;i&nbsp;就分别是不同的闭包实例,这个实例是在循环体执行的过程中创建的,保留了不同的值。补充:闭包的写法,无法保证按数组存放文件顺序读取文件内容,相当多个文件读取操作并行进行,根据文件大小决定读取的快慢;而forEach是可以的保证顺序读取;事实上以上这种写法并不常见,因为它降低了程序的可读性,故不推荐使用。大多数情况下我们可以用数组的&nbsp;forEach&nbsp;方法解决这个问题://callbackforeach.jsvar&nbsp;fs = require('fs');var&nbsp;files = ['a.txt', 'b.txt', 'c.txt'];files.forEach(function&nbsp;(filename) {fs.readFile(filename, 'utf-8',&nbsp;function&nbsp;(err, contents) {console.log(filename + ': ' + contents);});});
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Node.js