Является ли хорошая идея для вложенных XMLHttpRequests с несколькими замыканиями? - PullRequest
1 голос
/ 17 ноября 2009

У меня есть скрипт Greasemonkey, который работает на странице результатов поиска на видео-сайте. Функция скрипта - взять ссылку на JavaScript, открывающую новое окно с флеш-плеером, перепрыгнуть через несколько циклов перенаправления и вставить обычную ссылку на нужный 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
  } 
}

Ответы [ 3 ]

3 голосов
/ 17 ноября 2009

Что ж, вы могли бы улучшить читабельность, создав отдельные функции для каждого этапа, затем выполнить этап 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!");
}
1 голос
/ 17 ноября 2009

Или, если это станет еще сложнее, вы можете портировать Promises на ваш любимый JavaScript-фреймворк. Программирование AJAX в корне нарушено. Я делал это в течение 5 лет - 40 000 строк JS позже - одна попытка найти решение.

1 голос
/ 17 ноября 2009

Когда все становится сложнее, вы можете рассмотреть конечный автомат. http://www.ibm.com/developerworks/library/wa-finitemach1/

...