【问题标题】:Is nested XMLHttpRequests with multiple closures a good idea?具有多个闭包的嵌套 XMLHttpRequest 是个好主意吗?
【发布时间】:2009-11-17 18:52:29
【问题描述】:

我有一个 Greasemonkey 脚本,它在视频网站的搜索结果页面上运行。该脚本的功能是获取一个 javascript 链接,该链接打开一个带有 Flash 播放器的新窗口,跳过一些重定向箍,并插入一个指向所需 FLV 文件的常规链接。

我已更改脚本以执行与 en.wikipedia.org 相同但结构上相同的操作。我的问题是 3 个嵌套闭包和嵌套 xmlhttprequests 是否是解决此问题的最佳方法。


// ==UserScript==
// @name                wiki mod example
// @namespace         http://
// @description         example script
// @include  *wikipedia.org*
// ==/UserScript==

var candidates = document.getElementsByTagName("a");

for (var cand = null, i = 0; (cand = candidates[i]); i++) {
  if (cand.href.match(/\/wiki\/W/)) { // for all articles starting with 'W'
    var progress = document.createElement('span');
    progress.appendChild(document.createTextNode(" Start"));
    cand.parentNode.insertBefore(progress, cand.nextSibling);
    progress.addEventListener("click",
    function(link1) { return function() { // link1 is cand.href
      this.innerHTML = " finding...";

      GM_xmlhttpRequest({method:"GET",url:link1,
        onload:function(p) { return function(responseDetails) {
          // p is is the current progress element
          // the first linked article starting with 'S' is *special*
          var link2 = responseDetails.responseText.match(/\/wiki\/S[^"]+/);
          if(!link2) { p.innerHTML = "failed in request 1"; return;}

          GM_xmlhttpRequest({method:"GET",url:"http://en.wikipedia.org"+link2[0],
            onload:function(p2) { return function(responseDetails) {
              // p2 is p, ie. progress
              // link3 would contain the URL to the FLV in the real script
              var link3 = responseDetails.responseHeaders.match(/Content-Length.+/);
              if(!link3) { p2.innerHTML = "failed in request 2"; return;}

              var elmNewContent = document.createElement('p');
              elmNewContent.appendChild(document.createTextNode(link3));
              p2.parentNode.insertBefore(elmNewContent, p2.nextSibling);
              p2.innerHTML = " <em>Done</em>";
            }}(p) // 3rd closure
          }); // end of second xmlhttprequest

        }}(this) // 2nd closure
      }); // end of first xmlhttprequest

    }}(cand.href), true); // 1st closure and end of addeventlistener
  } 
}

【问题讨论】:

  • 看起来像经典的异步代码流。有什么问题?
  • 问题是这是我第一次尝试编写一个greasemonkey 脚本,我想确保我做对了。这与其说是“这段代码有问题”的问题,不如说是“这段代码有异味”的问题。
  • @Bribles:当然可以。 [嵌套] 异步代码流总是看起来很臭,但没有串行意大利面条代码那么臭;)

标签: javascript xmlhttprequest greasemonkey closures


【解决方案1】:

嗯,你可以通过为每个阶段创建单独的函数来提高可读性,然后让阶段 1 调用阶段 2,等等。所以,而不是

request({onload: function(response) {
    request({onload: function(response) {
        request({onload: function(response) {
            alert("psych!");
        }});
    }});
}});

你应该有

request({onload: doTheNextThing});

function doTheNextThing(responseObject) {
    request({onload: doTheRightThing});
}

function doTheRightThing(responseObject) {
    request({onload: doTheLastThing});
}

function doTheLastThing(responseObject) {
   alert("psych!");
}

【讨论】:

  • 我相信你的回答强调的是我有太多匿名函数。
【解决方案2】:

当这变得更复杂时,您可能会考虑使用状态机。 http://www.ibm.com/developerworks/library/wa-finitemach1/

【讨论】:

    【解决方案3】:

    或者,如果它变得更复杂,您可以将 Promises 移植到您最喜欢的 JavaScript 框架。 AJAX 编程从根本上被破坏了。我已经做了 5 年了 - 40,000 行 JS 之后这是一次解决方案的尝试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 2020-03-29
      • 2015-08-03
      • 2010-11-27
      • 2014-12-23
      相关资源
      最近更新 更多