2012-03-22 4 views
0

javascript 용 네임 스페이스 프레임 워크를 만들었습니다. 동적으로 HTML에 추가되는 일부 플러그인 (.js 파일)을로드하고 있습니다.스크립트 목록이 모두 자바 스크립트 (네임 스페이스 사용)에로드 될 때를 감지합니다.

코드를 단순화하려고합니다.

이 함수는 JS를 동적으로로드하는 데 사용됩니다. 콜백 함수는 .js 파일이로드 된 후에 호출됩니다. 다음 코드가 이미 실행되었다고 간주하십시오.

MYNAMESPACE.plugins = ["plugin1", "plugin2"]; 
MYNAMESPACE.getJS = { 
    get: function (url, callback) { 
     var script = document.createElement("script"); 
     var head = document.getElementsByTagName('head')[0]; 
     script.type = "text/javascript"; 
     script.src = url; 
     head.insertBefore(script, head.firstChild) 
     script.onload = callback; 
     script.onreadystate = callback; 
     return script; 
     } 
}; 

나는 다음과 같이 MYNAMESPACE.plugins에 포함 된 플러그인을로드하는 init 함수가 있습니다

내 HTML에서
MYNAMESPACE.init = function (callback) { 
    for (index in MYNAMESPACE.plugins) { 
     plugin = MYNAMESPACE.plugins[index]; 
     MYNAMESPACE.getJS.get(plugin + '.js', function() 
     { 
       // This callback is executed when the js file is loaded 
     }); 
    } 
    // Here I want to execute callback function, but after all the callbacks in the for loop have been executed. Something like: if (alljsloaded) callback(); 
} 

나는 다음과 같은 스크립트 태그가 :

<html> 
    <head> 
    <script type="text/javascript"> 
     $(document).ready(function() { 
      MYNAMESPACE.init(); 

      // The following line is not executed correctlybecause init finished before the scripts are loaded and the functionOnPlugin1 is undefined. 
      MYNAMESPACE.functionOnPlugin1(); 
     }); 
    </script> 
    </head> 
    <body> 
    </body> 
</html> 

그리고 난을 다음과 같이 변경하고 싶습니다.

<html> 
    <head> 
    <script type="text/javascript"> 
     $(document).ready(function() { 
      MYNAMESPACE.init(function() { MYNAMESPACE.functionOnPlugin1(); }); 
     }); 
    </script> 
    </head> 
    <body> 
    </body> 
</html> 

하지만 모든 플러그인 스크립트가로드 된 후 콜백을 실행하도록 MYNAMESPACE.init() 함수를 수정하는 방법을 모르겠습니다.

아이디어가 있으십니까? 어쩌면 클로저 사용. 배열을 통한 루프

답변

3
  1. 사용 for(;;), 하지for(.. in ..).
  2. 함수에 카운터를 생성하고 스크립트가로드 될 때마다 카운터를 증가시킵니다. 스크립트의 수에 도달하면 콜백 함수를 호출하십시오.

코드 :

MYNAMESPACE.init = function (callback) { 
    var allPluginsLength = MYNAMESPACE.plugins.length; 
    var loadedCount = 0; 
    if (allPluginsLength === 0) callback(); // No plugins, invoke callback. 
    else for (var index=0; index<allPluginsLength; i++) { 
     plugin = MYNAMESPACE.plugins[index]; 
     MYNAMESPACE.getJS.get(plugin + '.js', function() { 
       // This callback is executed when the js file is loaded 
       if (++loadedCount == allPluginsLength) { 
        callback(); 
       } 
     }); 
    } 
} 

또한, 변화 당신의 getJS.get 방법. 현재 callback은 상태가 변경 될 때 항상 실행되므로 바람직하지 않습니다. 두 번 실행되는 콜백을 방지하기 위해, 다음을 사용할 수 있습니다

script.onload = function() { 
     callback && callback(); 
     callback = false; 
    }; 
    // onreadystatechange instead of onreadystate, btw. 
    script.onreadystatechange = function() { 
     if (this.readyState == 'complete') { 
      callback && callback(); 
      callback = false; 
     } 
    }; 
  • callback && callback() 콜백가 있는지 확인하기 위해 사용됩니다. 존재하면 호출됩니다.
  • 콜백을 호출 한 후 즉시 제거됩니다 (callback = null).
    스크립트가로드 될 때 onloadonreadystatechange 이벤트가 발생할 수 있기 때문에이 작업이 필요합니다. 제안 된 코드가 없으면 단일 스크립트에 대해 콜백이 여러 번 호출됩니다. 이 같은
+0

PS합니다. 플러그인이 없을 때 콜백을 호출하고 싶다면'if (allPlugins === 0) callback();'을 추가하십시오. –

+0

우수 답변. 왜 콜백 && 콜백() 및 왜 나중에 null로 설정하는지 이해가되지 않습니다. – Tony

+0

@ 토니 귀하의 스크립트 로더에서, 당신은'onload' ** 및 **'onreadystatechange' 이벤트를 사용하고 있습니다.스크립트로드가 끝나면 둘 다 실행될 수 있습니다. 설명을 보려면 업데이트 된 답변을 참조하십시오 (또한 onreadystate 대신 onreadystatechange를 사용하십시오. 후자는 존재하지 않는 방법입니다). –

1

일부 변경 작업을해야합니다 :

MYNAMESPACE.init = function (callback) { 
    var remaining = MYNAMESPACE.plugins.length; 
    for (index in MYNAMESPACE.plugins) { 
     plugin = MYNAMESPACE.plugins[index]; 
     MYNAMESPACE.getJS.get(plugin + '.js', function() 
     { 
       // This callback is executed when the js file is loaded 
       remaining = remaining - 1; 
       if (remaining === 0) 
       { 
        callback(); 
       } 
     }); 
    } 
}