2012-12-11 2 views
2

내 Firefox 확장 기능은 웹 사이트에서 애드온 기능에 액세스하는 데 사용할 수있는 JavaScript 기능을 제공합니다. 웹 사이트는이 함수를 호출하고 두 가지 콜백을 제공합니다.Firefox 확장 기능 (SDK)의 콘텐츠 스크립트가 이벤트 리스너를 추가합니다.

웹 사이트 코드 :

function onButtonClick() { 
    var callbackSuccess = function() { alert("Yeah!"); }; 
    var callbackError = function() { alert("Oh no!"); }; 
    if (window.magicAddon) { // Check if my addon is installed 
    magicAddon.doStuff(callbackSuccess, callbackError); 
    } 
} 

내용 스크립트 : 첫 번째 전화에서 잘 작동하지만, 다음에 웹 사이트가 doStuff을 (호출

unsafeWindow.magicAddon = { 
    doStuff: function(callbackSuccess, callbackError) { 
    // Bind the two callbacks to events. The addon will fire one of them 
    self.port.on("doStuffSuccess", callbackSuccess); 
    self.port.on("doStuffError", callbackError); 

    // Fire the event that lets the addon do stuff 
    self.port.emit("doStuff"); 
    } 
}; 

), 새로운 청취자가 추가 up과 alert()가 두 번 실행됩니다. 다음 번에는 세 번의 경고가 있습니다.

청중들이 어떻게 합쳐지는 것을 우아하게 피할 수 있을지 아십니까? 이벤트 유형을 완전히 지울 수 있습니까?

지금까지 일을하지 무엇 : 다시 화재 클리어, 다른 하나는 유지하고, 다음과 함께 추가 오직 하나 내가 두 콜백 이벤트를 가지고 있기 때문에

  • 대신 self.port.once(..) 사용.
  • 새 콜렉션을 등록하기 전에 이전 콜백 참조가 없기 때문에 이전 콜렉션을 self.port.removeListener으로 제거하십시오.

문제는 그가 한 콜백 리스너를 사용하기 때문에 self.port.once(..)를 사용할 수있는 것만, How to remove an event listener?과 비슷한 것 같다.

+0

예,'unsafeWindow'는 안전하지 않고 http://bit.ly/rJbtA2를 읽었지만'document.body.appendChild (script)'는 나에게 훨씬 나아 보이지 않습니다 ... – Hannobo

답변

1

당신은 self.port.once를 사용하여 수동으로 다른 콜백 제거 할 수 있습니다 : 당신이 이벤트가 완전히 입력을 취소 할 수 있도록, 당신이 그렇게 할 수있어,

doStuff: function(callbackSuccess, callbackError) { 
    // Bind the two callbacks to events. The addon will fire one of them 
    self.port.once("doStuffSuccess", function() { 
    callbackSuccess(); 
    self.port.removeListener(callbackError); 
    }); 
    self.port.once("doStuffError", function() { 
    callbackError(); 
    self.port.removeListener(callbackSuccess); 
    }); 

    // Fire the event that lets the addon do stuff 
    self.port.emit("doStuff"); 
} 

당신은 콘텐츠 스크립트에있어를 주요 부가 기능 코드에서만 사용하고 하위 수준 API를 사용합니다.

그러나 안전하지 않으므로 unsafeWindow은 이러한 종류의 기능을 제공하지 않는 것이 좋습니다. API 비동기를 유지 관리하는 경우 콘텐츠 스크립트와 페이지간에 postMessage 파이프 라인을 사용하여 동일한 작업을 수행 할 수 있습니다. 사용자가 자신의 웹 사이트에 postMessages 호출의 추상화를 표시 할 수있는 별도의 자바 스크립트 파일을 제공합니다 (예 : magicAddon.doStuff()). 원하는 경우 웹 사이트에서 추가 기능의 스크립트를 자동으로 삽입 할 수도 있습니다.

이 메커니즘을 처리하는 것은 좀 더 복잡하지만 분명히 unsafeWindow의 사용을 피할 수 있습니다.

콘텐츠 스크립트 통신에 대한 자세한 내용은 here을 참조하십시오.

희망 하시겠습니까?

업데이트 :

doStuff: function() { 
    var executing = false; 

    return function(callbackSuccess, callbackError) { 
     if (executing) 
     return; 

     executing = true; 

     // Bind the two callbacks to events. The addon will fire one of them 
     self.port.once("doStuffSuccess", function() { 
     executing = false; 
     callbackSuccess(); 
     self.port.removeListener(callbackError); 
     }); 
     self.port.once("doStuffError", function() { 
     executing = false; 

     callbackError(); 
     self.port.removeListener(callbackSuccess); 
     }); 

     // Fire the event that lets the addon do stuff 
     self.port.emit("doStuff"); 
    } 
}() 

주 말에 () : 귀하의 코멘트에 대답하기 위해, 당신은 doStuff 통화 활동을 추적하는 변수가 필요합니다.기본적으로 이런 식으로 끝에서 doStuff으로 설정된 함수는 처음에 할당 한 함수의 결과입니다. 그런 식으로 executing 변수가있는 doStuff 메서드에 대한 클로저를 만들고 doStuff 실행이있는 경우 추적을 유지하고 다른 doStuff 호출을 무시하고 완료 될 때까지 추적을 유지합니다.

참고 :이 경우 자바 스크립트에는 필요하지 않지만이 함수가 '자체 실행'임을 확인하기 위해 괄호 안에 해당 함수를 래핑하는 것이 좋습니다. doStuff : (function() {.. .}())

이 작업에는 magicAddon의 개체 속성을 사용할 수도 있지만이 경우 해당 개체가 노출됩니다.

+0

고맙습니다 , 그것은 훌륭한 아이디어입니다. 그러나 한 가지 후속 질문 : doStuff는 사용자 상호 작용이 있으며 사용자가 점심 식사 중간에 간다면 1 시간 이상 걸릴 수 있습니다. 웹 사이트가 콜백을 기다리지 않고 두 번 함수를 호출하면 두 청취자 모두 콜백을받으며 콜백 4 개가 종료됩니다. 그것에 관한 어떤 생각? – Hannobo

1

첫 번째 호출에서 응답을 받기 전에 웹 사이트가 magicAddon.doStuff()으로 다시 전화 할 가능성을 고려해야합니다. 따라서 어느 시점에서든 하나 이상의 호출이 실행될 수 있습니다. 올바른 수신기를 호출해야합니다. 또한 콜백이 발생하면 두 리스너를 모두 제거해야합니다. 그렇지 않으면 메모리가 누출됩니다. doStuff 이벤트를 처리하는 코드를 매개 변수로 호출 ID를 얻고 있는지 확인하기 위해 다시 doStuffSuccess 또는 doStuffError 이벤트에 보낼 필요 -

doStuff: function(callbackSuccess, callbackError) { 
    // Generate a random call ID 
    var callID = Math.random(); 

    // Bind the two callbacks to events. Make sure to only act on events with the 
    // right call ID. 
    function onSuccess(id) { 
    if (id == callID) { 
     callbackSuccess(); 
     removeListeners(); 
    } 
    } 
    function onError(id) { 
    if (id == callID) { 
     callbackError(); 
     removeListeners(); 
    } 
    } 
    function removeListeners() { 
    self.port.removeListener("doStuffSuccess", onSuccess); 
    self.port.removeListener("doStuffError", onError); 
    }; 
    self.port.on("doStuffSuccess", onSuccess); 
    self.port.on("doStuffError", onError); 

    // Fire the event that lets the addon do stuff 
    self.port.emit("doStuff", callID); 
} 

이 전화를 식별하는 임의의 호출 ID를 사용하여 여기에이 작업을 수있는 방법입니다 올바른 콜백이 호출됩니다.

+0

당신의 생각도 마찬가지입니다. 고마워요. 왜 당신은'self.port.removeListener (type, callback)'을 사용하고 있으며 다른 것들은'self.port.removeListener (callback)'을 사용합니까? 둘 다 맞습니까? – Hannobo

+0

@Doug : 아니요, 'type' 매개 변수는 선택 사항이 아닙니다. [documentation] (https://addons.mozilla.org/en-US/developers/docs/sdk/1.13/modules/sdk/event/target)을 참조하십시오. .html # removeListener % 28type % 2C % 20listener % 29). 이것은 단순히 ZER0 코드에서 실수로 보이는 것입니다. –

관련 문제