【问题标题】:Practise for hell asynchronous function nodeJs地狱异步函数nodeJs的实践
【发布时间】:2018-05-16 11:15:44
【问题描述】:

我正在做一个学生项目。我的目标是收集数据并存储它。 我将 nodeJs 与 express 一起使用,然后在 ThemoviesDb 上使用 superagent 运行查询以收集电影,然后将它们存储在 neo4j 上。

这是我的例子:

app.get('/', function(req,res){

var hostname = "api.themoviedb.org/3";
var path = "/movie/";



// random id, to store random film  
for(i=0;i<39;i++){
    randomId = Math.floor(Math.random() * 500) + 80;
    console.log(' --------------------- Random id is     ---------------------- ' + randomId);
    superagent.get(hostname + path + randomId)
        .query({ api_key: api_key, append_to_response : 'credits' })
        .end((err, res) => {
            if (err) { 
                if(err.status_code = '34') {
                    return console.log('id : ' + randomId + 'ne correspond pas à un film')
                }
                else{
                    return console.log(err);
                }
            }
            cpt ++;

            title = res.body.original_title;

            if(title){  // Test if title isn't nul, undefined, Nan, empty or 0 to add it
                console.log('randomId --> '  + res.body.id + '--> ' + title );
                if(!Filmadded.includes(film)){
                Filmadded.push(film);
            }       
            }               
        });

    }
                console.log('cpt : ' + cpt + '/39');
res.send('it works' + i );
});

我只是在执行一个循环( 39 因为 api 的限制是 40 ) 对于每一个我都会提出要看电影的请求。

结果:

如您所见,我首先显示所有 id,然后显示与 id 匹配的标题。 --> 我想等到请求结束后再继续。 我看起来答应了,但我没有一切。

然后我认为我在 id / film 上的问题是由于这个。

感谢您的帮助,对不起我的英语

【问题讨论】:

  • 变量film 和Filmadded 无处可寻,cpt 也是如此。你能发布完整的代码或指向一个 git repo 吗?

标签: javascript node.js asynchronous promise request


【解决方案1】:

您的superagent() 调用是异步的。因此,它不会阻塞,您的 for 循环只会运行到完成,同时启动所有 39 个 superagent() 调用。您可能可以编写代码以并行运行所有这些(如果目标主机允许的话),但是由于您要求能够一个接一个地运行它们,因此这里是使用 superagent() 和 @987654325 的承诺功能的函数的实现@ 序列化 for 循环中的异步调用,使其运行一个,等待它完成,然后运行下一个:

app.get('/', async function(req, res){

    let hostname = "api.themoviedb.org/3";
    let path = "/movie/";

    // random id, to store random film  
    for (let i = 0; i < 39; i++) {
        let randomId = Math.floor(Math.random() * 500) + 80;
        console.log(' --------------------- Random id is     ---------------------- ' + randomId);
        try {
            let result = await superagent.get(hostname + path + randomId)
                .query({ api_key: api_key, append_to_response : 'credits' });
            cpt ++;

            let title = result.body.original_title;

            if (title) {  // Test if title isn't nul, undefined, Nan, empty or 0 to add it
                console.log('randomId --> '  + res.body.id + '--> ' + title );
                if (!Filmadded.includes(film)) {
                    Filmadded.push(film);
                }       
            }               
        } catch(err) {
            if(err.status_code = '34') {
                console.log('id : ' + randomId + 'ne correspond pas à un film')
            }
            else{
                console.log(err);
            }   
        }
        console.log('cpt : ' + cpt + '/39');
    }
    res.send('it works' + i );
});

此外,您需要确保声明您正在使用的所有变量,以便它们是意外的全局变量,当有其他请求也在运行时可能会发生冲突。

此代码的其他看起来不正确的地方,但我不知道您的意图:

  1. 变量cpt 看起来需要初始化并在某处声明。
  2. 变量Filmadded 可能需要在本地范围内(而不是在您的服务器上运行多个请求时可能发生冲突的某些更高范围的变量)。
  3. 目前尚不清楚当superagent() 调用失败时,您实际上打算如何处理错误。在这里它只记录错误,但如果遇到错误,您可能需要能够返回错误状态。

【讨论】:

    【解决方案2】:

    正如你所说,superagent 的get 函数是异步的,这意味着事件循环不会等待函数完成,然后再执行下一个命令。因此,循环启动了 40 次循环执行,其中包括创建一个随机 id,然后使用具有该 id 的 superagent。所以我们在讨论两个动作——一个是同步的,第二个是异步的。

    让我们以另一种方式来看待它。假设我们有以下循环:

    for(i=0; i<39; i++) {
        const randomId = Math.floor(Math.random() * 500) + 80;
        console.log("RANDOM IS: ", randomId);
        setTimeout(function(){
            console.log("PRINT AGAIN: ", randomId);
        }, 10000);
    }
    

    您将在此处获得 40 行“RANDOM IS: [random_number]”以连续方式显示,仅在 10 秒后您将获得 40 行“PRINT AGAIN: [random_number]”,这就是因为您为第二次记录设置了 10 秒的超时时间。

    您可以将 10 秒的 setTimeout 与异步函数进行比较 - 仅在异步函数中,您无法真正判断函数何时完成。所以基本上你所拥有的类似于上面的例子 - 40 个随机数的日志记录,以及一些随机定时的 Promise 执行。

    所以你可能要考虑的是使用 js Array 的 reduce 函数进行 Promise 链接,或者使用 es6 async await function notation

    您可以将超级代理函数用作 Promise,并改用 thencatch。然后,链接 Promise 意味着您等待一个 Promise 完成,然后才执行下一个 Promise。

    【讨论】:

      猜你喜欢
      • 2011-09-08
      • 2019-06-21
      • 2015-01-05
      • 1970-01-01
      • 2021-07-14
      • 1970-01-01
      • 2017-09-02
      • 2017-03-26
      • 1970-01-01
      相关资源
      最近更新 更多