【问题标题】:Preventing nested callbacks in JavaScript that uses iteration防止使用迭代的 JavaScript 中的嵌套回调
【发布时间】:2015-01-23 15:09:51
【问题描述】:

目前我正在使用 Promise 来尝试防止在我的代码中需要嵌套回调,但我遇到了挫折。在这种情况下,我使用节点的 request-promise 和cheerio 在服务器上模拟 jQuery。但是,有时我需要调用jQuery.each(),为每个<a> 元素创建一个请求。有什么方法可以使用 Promise 来防止这种嵌套回调?

request("http://url.com").then(function (html) { 
    var $ = cheerio.load(html);
    var rows = $("tr.class a");
    rows.each(function (index, el) {

        //Iterate over all <a> elements, and send a request for each one.
        //Can this code be modified to return a promise?
        //Is there another way to prevent this from being nested?

        request($(el).attr("href")).then(function (html) {
            var $ = cheerio.load(html);
            var url = $("td>img").attr("src");
            return request(url);
        })
        .then(function (img) {
            //Save the image to the database
        });
    });
});

【问题讨论】:

    标签: javascript jquery node.js promise cheerio


    【解决方案1】:

    这是我最终得到的最佳解决方案。我所做的一些偶然更改包括使用 url.resolve 来允许相对 URL 工作。

    var $ = require('cheerio');
    var request = require('request-promise');
    var url = require('url');
    
    var baseURL = "http://url.com";
    
    request(baseURL).then(function (html) {
        $("tr.class a", html).toArray(); 
    }).map(function (el) {
        return request(url.resolve(baseURL, jq.attr("href")));
    }).map(function (html) {
        var src = $("td>img", html).attr("src");
        return request(url.resolve(baseURL, src));
    }).map(function (img) {
        //Save the image to the database
    });
    

    感谢 Benjamin Gruenbaum 将我更改为 bluebird 中的 .map() 方法。

    【讨论】:

      【解决方案2】:

      假设 Bluebird 承诺(其他库中的代码类似):

      Promise.resolve(request("http://url.com").then(function (html) { 
          var $ = cheerio.load(html)("tr.class a");
      })).map(function(el){ // map is `then` over an array
          return el.href;
      }).map(request).map(function(html){
          return cheerio.load(html)("td>img").src;
      }).map(request).map(function(img){
          // save to database.
      });
      

      或者,您可以为单个链接定义操作,然后对其进行处理。它看起来很相似。

      【讨论】:

      • @SLaks 等等,没关系 - 是的,我愿意。虽然他们使用 Bluebird - 他们不会将其方法暴露给外部(天知道为什么),因此需要解决
      • 那么它到底返回了什么?此外,您还缺少)
      • @SLaks 关于) - 我只是在then 之后关闭它。 Promise.resolve 所做的是采用 thenable 并将其转换为公开整个 API 的可信 Bluebird 承诺。 request-promised 所做的是剥离除 then/catch/finally 之外的所有方法(它只暴露那些)。
      • 我收到错误Possibly unhandled TypeError: expecting an array, a promise or a thenable,但我不确定这应该如何工作。 .map() 是蓝鸟的吗?但这不需要一系列承诺吗?而且你不会从第一个 .then() 返回任何东西,那么这将如何工作?
      猜你喜欢
      • 2013-01-12
      • 1970-01-01
      • 2021-10-26
      • 1970-01-01
      • 2018-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多