V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
InFaNg
V2EX  ›  Node.js

奇怪的 for 循环问题

  •  
  •   InFaNg · 2016-08-16 14:03:18 +08:00 · 2452 次点击
    这是一个创建于 3023 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码如下,每次运行后items中只有i=100时的情况

    var express = require('express');
    var cheerio = require('cheerio');
    var superagent = require('superagent');
    var items = [];
    
    var app = express();
    for(var i=1;i<100;i++) {
      app.get('/', function (req, res, next) {
        superagent.get('http://xxx/' + i + '.html')
          .end(function (err, sres) {
            if (err) {
              return next(err);
            }
            var $ = cheerio.load(sres.text);
            items.push($('.d1').attr('href'));
            res.send(items);
          });
      });
    }
    
    app.listen(3000, function () {
      console.log('app is listening at port 3000');
    });
    
    第 1 条附言  ·  2016-08-16 19:47:45 +08:00
    原来 var 是函数级的, let 是块级的,之前一直没注意

    还有一不小心把 express 写在 for 循环里面了😂
    bdbai
        1
    bdbai  
       2016-08-16 14:10:33 +08:00 via Android   ❤️ 1
    这是闭包教程的经典例子😂
    另外你这个逻辑似乎有点问题,回去重新写一下。
    lijsh
        2
    lijsh  
       2016-08-16 14:16:53 +08:00   ❤️ 1
    这个和闭包无关,你这里相当于创建了 100 个 app.get('/', fn)的路由处理, url 都一样的,估计是最后一个才起效。

    这里都不用 express ,你直接用 superagent 不就行了。
    wodesuck
        3
    wodesuck  
       2016-08-16 15:36:13 +08:00 via Android   ❤️ 1
    没点进来就知道是这样😂
    因为你里面的 function 实际是在 for 循环结束之后执行的,那时候 i 已经改变了
    for (var i ...) {
    function(i) {
    ...
    }(i);
    }
    试一下这样,把 i 作为参数传进去,可以避免受外部的 for 影响
    bdbai
        4
    bdbai  
       2016-08-16 15:37:09 +08:00   ❤️ 1
    给你一个改过的例子,用了一些略带花哨的 ES6 特性。要抓的东西你自己改一下吧。

    https://gist.github.com/bdbai/3c4d1507c47874efe002683465a7bc25
    zhqy
        5
    zhqy  
       2016-08-16 17:05:37 +08:00
    @lijsh 你这第一句话全说错了。
    Arrowing
        6
    Arrowing  
       2016-08-16 17:12:19 +08:00
    看了标题就想到了结果,果然是这样 😂
    还是闭包的问题啊。
    phxsuns
        7
    phxsuns  
       2016-08-16 17:17:49 +08:00
    是你的逻辑有点怪。
    创建了 100 个路由处理,还是同一个路由。
    那肯定只有一个结果了。
    zhouyg
        8
    zhouyg  
       2016-08-16 17:46:45 +08:00
    猜猜,果然就是闭包和异步引用的问题。
    isbase
        9
    isbase  
       2016-08-16 18:08:36 +08:00   ❤️ 1
    用 ES6 的 let

    var express = require('express');
    var cheerio = require('cheerio');
    var superagent = require('superagent');
    var items = [];

    var app = express();
    for(var i=1;i<100;i++) {
    let j = i;
    app.get('/', function (req, res, next) {
    superagent.get('http://xxx/' + j + '.html')
    .end(function (err, sres) {
    if (err) {
    return next(err);
    }
    var $ = cheerio.load(sres.text);
    items.push($('.d1').attr('href'));
    res.send(items);
    });
    });
    }

    app.listen(3000, function () {
    console.log('app is listening at port 3000');
    });
    Biwood
        10
    Biwood  
       2016-08-16 18:27:59 +08:00
    这种基础的 JS 面试常见知识点在 V2 论坛都快成月经贴了
    xcodebuild
        11
    xcodebuild  
       2016-08-16 19:15:15 +08:00 via Android
    InFaNg
        12
    InFaNg  
    OP
       2016-08-16 19:24:32 +08:00 via Android
    @phxsuns for 写错位置了。。。。
    m31271n
        13
    m31271n  
       2016-08-17 16:16:39 +08:00
    看见标题,想到结果系列。

    涉及到的知识点:
    * var 的特性
    * 块级作用域
    * 作用域链
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1750 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 00:00 · PVG 08:00 · LAX 16:00 · JFK 19:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.