programing

Ajax 응답 내부에 반환된 js 파일 실행

javamemo 2023. 8. 23. 21:32
반응형

Ajax 응답 내부에 반환된 js 파일 실행

저는 jquery 3.2.1을 사용하는 HTML5 어플리케이션을 가지고 있습니다.

애플리케이션의 일부 - 검색 기능 - Ajax 요청을 합니다.에는 Ajax 요은이응며 HTML답, 여는이포함다니가 포함됩니다.<script>응용 프로그램과 동일한 서버에서 호스팅되는 js 파일에 연결하는 태그입니다.

- 가 그서아코에 - 로요하을다 - 아스청것 ID가 ▁div▁id▁the▁a▁so▁looks▁making▁for에▁the▁request▁the다▁response▁to▁writing▁ajax▁code▁and▁ajax니입것▁like▁-▁this▁the한위로기.#ajaxContent:

$.ajax({
    url: $('#searchRegulations').attr('action'),
    type: 'post',
    cache: false,
    data: $('#searchRegulations').serialize()
 }).done(function (response, status, xhr) {
        if (response) {
            $('main .content').hide();
            $('#ajaxContent').html(response).show();
            return false;
        }
    }
});

가 사를하면을 하면,#ajaxContent나는 그것을 볼 수 있습니다.<script>태그는 Ajax 응답에 포함됩니다.

enter image description here

또한 확인하기 위해 네트워크 탭을 확인했습니다./js/search_regulations.js올바르게 로드되고 있으며 200개의 응답을 제공합니다.

에 안에.search_regulations.js에 존재하는 일부 필터를 전환하는 일부 jquery가 있습니다.#ajaxContent.

문제는 이 코드가 약 50%만 작동하는 것처럼 보인다는 것입니다.때 " " " " " "/" " " " " " " " " " " " " " " 를 추가합니다..active 안의 .browse-ctp__filters-data그리고 ID로 숨겨진 양식으로 작성합니다.#tmpFilters.

가 "는 "발사" .console.log('search_regulations.js firing');스크립트가 작동하는지 여부에 관계없이 매번 콘솔에 표시됩니다.

이상한 것은 Ajax 응답이 페이지에 기록된 후 코드를 내 콘솔에 잘라내거나 붙여넣으면 항상 예상대로 작동한다는 것입니다.

스크립트를 페이지로 가져오는 방식에 문제가 있습니까?

아래 스크립트를 붙여 넣었지만, 브라우저/아약스 응답 방식보다는 코드에 문제가 있다고 생각합니다.

$(function() {  

console.log('search_regulations.js firing');

/* toggle the active (applied) state on browse by filters */
/* @link https://stackoverflow.com/questions/48662677/switch-active-class-between-groups-of-include-exclude-buttons */
$(document).on('click', '.browse-ctp__filters-data .include, .exclude', function(){

    var $this = $(this);

    // Split name into array (e.g. "find_355" == ["find", "355"]) 
    var arr = $this.attr('name').split('_');


    // Toggle active class
    $this.toggleClass("active");
    if ($this.siblings().hasClass("active")) {
      $this.siblings().removeClass("active")
    }

    // Remove any existing instances of the filter from hidden form
    $('#tmpFilters input[value="exclude_'+arr[1]+'"]').remove();
    $('#tmpFilters input[value="find_'+arr[1]+'"]').remove();

    // If a filter has been applied then add it to hidden form
    if ($this.hasClass('active')) {
        $('#tmpFilters').append('<input type="hidden" name="tmpFilter[]" value="'+$this.attr('name')+'">');
    }
});    
}); 

제공된 바운티 관련 참고 사항:

저는 그것이 해결해야 할 사소한 문제가 아니기 때문에 현상금을 제시했습니다. - 아무도 실행 가능한 대답을 하지 않았다는 사실이 입증되었습니다.다음에 대한 올바른 답변을 기대합니다.

  1. jsfiddle 또는 동등한 기능을 사용하여 시연할 수 있습니다.
  2. 작동 방식/이유 설명
  3. 아약스 응답이 HTML과 js임을 이해합니다.js는 응답의 HTML 요소에 작용합니다.따라서 "js를 글로벌 파일에 추가하기만 하면 됩니다."라고 말하는 것이 아니라 HTML과 js를 모두 응답에 포함시켜야 합니다. (js는 주어진 HTML 응답에 고유하며 응용 프로그램의 다른 부분에 따라 달라질 수 있기 때문에 글로벌하지 않습니다.)
  4. 제한을 하면 안 됩니다.setTimeout또는 무엇이든).사용자가 시간 초과 전에 HTML 응답에 반환된 UI 요소(예: 버튼)와 상호 작용하여 js가 실행되는 경우...그것은 우리가 지금 가지고 있는 것과 같은 문제로 이어집니다.그래서 그것은 제가 생각하는 한 유효한 해결책이 아닙니다.
  5. HTML5/jquery에서 이 문제를 해결할 수 없다면 이유를 설명하고 해결할 수 있는 다른 방법을 제안합니다.

jsfiddle은 ajax를 통해 반환된 HTML 및 스크립트 태그를 보여줍니다.

몇몇 사람들이 바이올린이나 데모를 요청했습니다.어떤 두 사람도 같은 결과를 얻을 수 없을 것입니다 - 그것이 바로 질문의 핵심입니다 - 그래서 저는 원래 하나를 만들지 않았습니다.다에기이록는 HTML반환다니됩음으로 작성된 되었습니다.#ajaxContent다음에 표시됩니다. http://jsfiddle.net/v4t9j32g/1/ - 이것은 브라우저의 개발 도구가 Ajax 응답 후에 표시하는 것입니다.반환되는 콘텐츠의 길이는 필터 단추의 로드를 가져오는 키워드 검색 기능에 대한 응답이므로 달라질 수 있습니다.또한 이 HTML 응답에는 다음 행이 포함되어 있습니다.<script src="/js/search_regulations.js"></script>여기서 문제가 있는 js가 발견되고 그 전체 내용이 이 질문에 표시됩니다 - 다음을 포함하는 비트.console.log('search_regulations.js firing')

제가 보는 문제 중 하나는 당신이 그들을 구속하고 있다는 것입니다.onclick같은 요소에 여러 번...

js는 Ajax 요청을 통해 여러 번 로드될 수 있으므로 이벤트를 다시 첨부하기 전에 먼저 분리하는 것이 중요합니다.

또 또다문코실있것다입니다는행고하에 있는 코드를 입니다.$(document).ready, 준비되었을 때), 당신은 이벤즉(HTML-Document가 ▁the▁in▁code▁event▁(이▁the▁html▁be다'니것▁off▁html▁better입▁run것▁ready▁you▁howeverthat)에서 코드를 실행하는 것이 더 입니다.$(window).loadevent (로딩되었을 때 늦게되는 이벤트는 다음과 같습니다.

:

$(window).load(function() {  

    console.log('search_regulations.js firing');

    //off: detach the events
    //on: attach the events
    $('.browse-ctp__filters-data .include, .exclude').off('click').on('click', function(){
        ...
    }
}); 

여러분들이 댓글로 얘기하신 것 외에 제가 한번 답변을 해보도록 하겠습니다.

이벤트 기반

JS는 이벤트 중심이므로 이벤트가 발생할 때 스크립트를 즉시 로드하여 기능을 실행할 필요가 없습니다.더 나은 접근 방식은 페이지 로드에 필요한 모든 것을 로드하고 이벤트 청취자를 추가하는 것입니다. 이것은 훨씬 더 나은 사용자 경험(http 요청 수 감소)과 훨씬 더 나은 코드 완성도를 제공합니다.

TL;DR

일반적으로 HTML 파일에서 다음과 같은 작업을 수행합니다.

<script src="/js/main.js">  
<script src="/js/search_regulations.js" async>  <!-- bonus tip! google "async script tag" -->

이렇게 하면 필요한 모든 j를 로드할 수 있습니다.

을 명심하세요.search_regulations.js jQuery로 .on그러나 스크립트가 이벤트 수신기를 추가할 때 html이 없었기 때문에 이를 확인하는 것이 좋습니다.

이게 왜 더 나은 거지?

  • 이제 한 파일이 다른 파일을 로드하는 쉬운 사례가 있습니다.앞으로 더 많은 기능과 더 복잡한 코드를 추가할 수 있습니다.서로 로드하는 스크립트 체인이 있는 경우 디버깅하기가 어렵습니다.
  • .search_regulations.js로드할 파일(모바일 네트워크에 있는 경우)/파일 크기가 커져 사용자 환경이 좋지 않을 수 있습니다.
  • 응용프로그램을 통해 코드를 다시 사용할 수 있습니다.search_regulations.js

참고:

  • @코요코세르지오는 이미 당신의 질문에 답했습니다. 그의 첫 번째 요점을 보세요.
  • 바스토스의 답변을 "강화"한 @yts에게도 공로를 돌려야 합니다.

은 여러분의 그서다음문해것입결다니할제를신당 문제를 해야 합니다.search_regulations.js스크립트:

$(document)
  // Detach the event handler to prevent multiple/repeat triggers on the target elements.
  .off('click.toggleActive', '.browse-ctp__filters-data .include, .exclude')
  // Attach/re-attach the handler.
  .on('click.toggleActive', '.browse-ctp__filters-data .include, .exclude', function(){
    ... put your code here ...
  });

하지만 가 이 답을 쓰는 주된 목적은 여러분이 스크립트의 문제를 볼 수 있도록 하는 것입니다.

그리고 궁금하다면, 여기 제가 데모에 사용했던 스크립트가 있는데, 약간 수정되었습니다.

https://codepen.io/anon/pen/RBjPjw.js

요구 사항 정보

이 문제의 해결책은 HTML5/jQuery 또는 이전 HTML 버전과 네이티브 Javascript의 조합을 사용하여 사용할 수 있습니다.jQuery와 같은 라이브러리를 사용하는 유일한 이유는 오래된 브라우저를 동일한 수준으로 지원하거나 버그를 수정하고 개발자 그룹 간에 표준 프레임워크를 공유하기 위해서입니다.

또한, 제 생각에는 문제를 해결하는 데 필요한 몇 줄의 코드를 어디에 두어도 상관이 없으며, 페이지의 헤드 섹션이나 페이지 하단 또는 자주 다시 로드되는 Ajax 응답 페이로드 내의 바운티 요구 사항에 대해 입력할 수 있습니다.

이슈 정보

진짜 트릭은 클릭 이벤트의 실행을 달성하기 위해 사용하는 방법에 있습니다. 반복되는 Ajax 응답에 있는 스크립트 내에서 실행을 선택하는 것이 어느 시점에서 CAD를 실패하게 만듭니다.

Ajax 요청이 발생할 때마다 응답의 스크립트가 새 이벤트 수신기를 추가합니다.이러한 값은 브라우저가 어떤 이유(메모리 부족, 이벤트 스택 부족 또는 클릭 이벤트 경합 조건)로 인해 오류가 발생할 때까지 지속적으로 요약됩니다.

솔루션 정보

따라서 Ajax 요청/응답이 발생할 때마다 이벤트를 추가하지 않는 것이 문제 해결 방법입니다.이는 간단한 "캡처 단계 이벤트 위임"(불행히 자주 사용되지 않음)으로 쉽게 해결할 수 있는 작업입니다.

이벤트 수신기는 "문서" 노드 자체, "html" 요소 또는 "본문" 요소가 될 수 있는 상위 노드 중 하나에 한 번만 추가되므로, 초기 페이지 로드 후 DOM에 항상 존재하는 하나의 요소에 한 번만 추가됩니다.

이 요소는 페이지의 모든 클릭을 캡처하는 역할을 하며, 나중에 Ajax 요청에 의해 현재 존재하거나 로드됩니다. 이 요소는 페이지의 전체 수명 동안 그렇게 작동합니다. 제안된 이벤트를 설정/파괴할 필요가 없습니다.이는 아마도 작동하지만 브라우저 엔진에서 더 많은 워크로드를 생성하고, 더 많은 메모리를 소비하며, 더 많은 코드를 요구하고, 전반적으로 더 느리고 불필요하게 까다롭게 말할 수 있습니다.

코드 샘플

두 가지 CodePen 예제를 설정했습니다.

위임 1에는 HEAD 섹션에 이벤트 처리 코드가 있으며, 제한 사항이나 알 수 없는 기타 특이점이 없는 경우 이러한 문제를 처리하는 것이 좋습니다.이 버전의 이점은 코드를 더 짧게/더 빠르게 유지 관리할 수 있다는 것입니다.

위임1

위임2는 Ajax 응답에 이벤트 처리 코드가 있으며 지속적으로 로드되는 HTML/JS에 대한 요구 사항을 충족해야 합니다.수신기를 한 번만 설치하고 여러 이벤트가 경합 및 중복되지 않도록 하는 검사가 있습니다.

위임2

예제의 Javascript 코드는 관련 설명을 포함하고 있으며 구현된 전략을 설명하기에 충분해야 하며 이를 최대한 단순화하고 다른 유사한 경우에 재사용할 수 있습니다.

되었으며, 는 " 한러예오는를브래며으염었두작이성되다고두에니를, 새운브저는다같노합 ▁mores▁api다▁these"와 같은 더 강력한 를 노출합니다.element.matches(selector)이벤트 위임에 매우 유용합니다.저는 일부러 더 광범위한 지원을 위해 그것을 사용하는 것을 피했습니다.

HTML에서 < script > 태그를 제거하고 수동으로 스크립트 태그를 생성하여 DOM에 추가해야 합니다.기본적으로 다음을 통해 Html을 JS로 변환할 수 있습니다.

var $html = $(data.Html)

그런 다음 다음과 같은 모든 스크립트 태그를 꺼냅니다.

 var scripts = [];
        $html.each(function(i, item) {
            if (item instanceof HTMLScriptElement) {
                scripts.push(item);
            }
        });

그런 다음 DOM에 추가하기 전에 html에서 <script > 태그를 모두 제거해야 합니다.

$html.find("script").remove();

$("placeToAddHtml").append($html);

태그가 제거된 HTML이 추가되면 마지막에 DOM에 각 스크립트를 수동으로 추가할 수 있습니다.

           for (var i = 0; i < scripts.length; i++) {
                var script = document.createElement('script');

                $(scripts[i]).each(function() {
                    $.each(this.attributes, function(j, attrib) {
                        var name = attrib.name;
                        var value = attrib.value;
                        script[name] = value;
                    });
                });

                script.text = scripts[i].innerHTML;
                document.body.appendChild(script);
            }

이것이 당신이 의도한 대로 작동하기를 바랍니다!

편집: 끌어낸 모든 스크립트가 서로 의존하는 경우 여기에 스크립트 태그를 동시에 추가하는 방식으로 작성해야 할 수도 있습니다.이렇게 하면 한 번에 내부적으로 다른 모든 태그가 포함된 하나의 거대 스크립트 태그만 추가할 수 있습니다.

플랫 타이머를 구현하지 않고 레이스 상태가 발생할 가능성을 피하기 위해 두 개의 요소(여러 개가 필요한 경우를 지원하는 스크립트 또는 스크립트 배열, 문자열화된 HTML 마크업을 포함하는 두 번째 요소)를 반환하는 json 개체와 같이 스크립트와 html을 구분하는 Ajax 응답을 반환해야 합니다.

아약스의 json 응답 예:

{
    "script": "/yourscript.js",
    "html": "<p>Your markup...</p>"
}

은 이 (으)로 됩니다.xhrResponse간결하게 하기 위하여 아래에

돔에 적용하기 전에 돔 요소를 로드하기 전에 스크립트에 대한 사전 로드 태그를 추가하면 로드 없이 백그라운드에서 해결되기 시작하므로 전체 로드 타임라인을 최소화하고 진행 중인 레이스 상태의 가능성을 줄이는 데 도움이 됩니다.

document.getElementsByTagName('head')[0].appendChild( '<link rel="preload" href="' + xhrResponse.script + '" as="script">' );

스크립트를 실행하지 않고 백그라운드에서 스크립트를 로드하기 시작하므로 나중에 스크립트 태그를 돔에 적용할 때 즉시 적용할 수 있습니다.

그런 다음 돔 요소를 추가하고 새 돔 콘텐츠가 해결된 후 스크립트를 적용할 수 있습니다.또는 json 응답에 직접 마크업을 전달하거나, 템플릿 파일에 대한 링크를 반환하여 위에서 언급한 템플릿 자체의 프리로드 방법과 함께 제공할 수 있습니다.내용에 대한 문제를 피할 수 있는 가능성에 더 관심이 있는 경우에는 후자를 수행합니다.대역폭 및 지연 시간이 더 중요한 경우 전자를 수행합니다.사용 사례에 따라 두 가지 모두에 몇 가지 사소한 주의 사항이 있습니다.

document.getElementsByTagName('head')[0].appendChild( xhrResponse.html );

그러면 적용된 HTML 콘텐츠가 돔 내에서 해결되었는지 확인할 수 있습니다.임의 대기 타이머는 사용자가 필요 이상으로 오래 기다리게 할 가능성이 높기 때문에 이를 위한 좋은 방법이 아니며, 때때로 네트워크 병목 현상으로 인해 임의 타이머 길이 전에 내용이 해결되지 않으면 스크립트가 가끔 질식할 수 있습니다(라인에서 템플릿을 제공하는 경우 더 많은 문제).문자열화된 html 마크업 대신 k) 또는 최종 사용자가 현재 사용 가능한 메모리가 부족한 경우(이전 시스템, bzillion 탭이 열려 있거나 직접 문자열화된 서비스를 제공하더라도 매우 큰 html 페이로드).

동적으로 추가된 돔 콘텐츠가 올바르게 해결되었는지 확인하려면 이 답변을 참조하십시오.

이 문제가 해결되면 다음과 같은 방법으로 스크립트 요소를 적용합니다.

var script = document.createElement('script');
script.src = xhrResponse.script;
script.async = true; // use false here if you want synchronous loading for some reason
document.head.appendChild(script);

앞에서 언급한 사전 로드 태그는 스크립트가 이 시점까지 브라우저에 의해 이미 현지화되었거나 이미 거의 완료되었는지 확인해야 합니다.그런 다음 준비 상태 이벤트 수신기에서 완료되었는지 확인하여 문제가 계속 발생하는지 여부를 확인할 수 있습니다.

script.onreadystatechange = function() {
    if (script.readyState === "complete") {
        // debug stuff, or call an init method for your js if you really want to be sure it fired after everything else is done.
    }
}

위의 준비 상태 수신기에서 사전 로드가 논리의 이 부분보다 먼저 해결되면 준비 상태가 변경되지 않으며(이미 완료되었기 때문에) 논리의 이 부분이 실행되지 않습니다.DOM 콘텐츠의 무게에 따라 이 기능이 사용자에게 적용되거나 적용되지 않을 수 있습니다.


이 방법을 사용하면 올바른 순서로 로드할 수 있으며 스크립트와 마크업을 분리할 수 있으므로 현재 또는 미래의 어느 시점에서도 서로 독립적으로 재활용할 수 있습니다.

이것을 아약스 매개 변수에 추가하면 모두 괜찮을 것이라고 생각했습니다.

비동기: false

제가 생각하는 문제는 다음과 같습니다: 1.포함 및 제외는 동일한 기능을 트리거합니다.두 가지를 모두 처리하기 위해 내부 논리에 오류가 발생했습니다. (당신이 50%의 시간이 작동한다고 말했기 때문에) 2.HTML을 추가한 후 DOM을 업데이트해 보십시오.

   componentHandler.upgradeDom();

바로 뒤에

 $('#ajaxContent').html(response).show();

도움이 되길 바랍니다!!!

언급URL : https://stackoverflow.com/questions/51441480/executing-a-js-file-returned-inside-an-ajax-response

반응형