2009-11-17 2 views
1

비디오 사이트의 검색 결과 페이지에서 작동하는 Greasemonkey 스크립트가 있습니다. 스크립트의 기능은 플래시 플레이어로 새 창을 여는 자바 스크립트 링크를 사용하고 일부 리디렉션 후프를 건너 뛰고 원하는 FLV 파일에 대한 일반 링크를 삽입하는 것입니다.중첩 된 XMLHttpRequests는 여러 개의 클로저를 사용하는 것이 좋습니다.

나는 바보이지만 구조적으로 동등한 일을 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 
    } 
} 
+0

고전적인 비동기 코드 흐름처럼 보입니다. 뭐가 문제 야? –

+0

문제는 이것이 greasemonkey 스크립트를 작성하는 첫 번째 시도이며, 내가 올바르게하고 있는지 확인하고 싶습니다. 이것은 "이 코드 버그입니다"라는 질문과 "이 코드가 냄새가 난다"질문에 더 가깝습니다. – Bribles

+0

@Bribles : 예 물론. [중첩 된] 비동기 코드 흐름은 항상 냄새가 나긴하지만 직렬 스파게티 코드는 더 이상 냄새가 아닙니다.) –

답변

3

글쎄, 당신은 다음 단계 1 통화 2 단계 등 그래서, 대신

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

의 당신이

이 줄을 가지고, 각 단계에 대해 별도의 기능을 작성하여 가독성을 향상시킬 수
+0

코드의 평균 들여 쓰기 수준을 줄입니다. – Bribles

+0

당신의 대답이 강조하는 것은 제가 너무 많은 익명의 기능을 가지고 있다는 것입니다. – Bribles

1

또는 더 복잡 해지면 Promises을 좋아하는 JavaScript 프레임 워크에 이식 할 수 있습니다. AJAX 프로그래밍은 근본적으로 손상되었습니다. 나는 5 년 동안 그것을 해왔다. JS의 40,000 줄은 나중에이 한 번의 시도였다.

관련 문제