JavaScript에서 잠금을 구현하는 방법


83

lockC # 과 동등한 것을 JavaScript에서 어떻게 구현할 수 있습니까?

그래서 제가 생각하는 간단한 사용 사례를 설명하려면 다음과 같습니다.

사용자가 버튼을 클릭합니다 B. Bonclick 이벤트를 발생시킵니다. 경우 Bevent-state이벤트 대기 위해 B에있을 ready-state전파하기 전에. 경우 Bready-state, B잠겨로 설정 event-state한 후, 이벤트 전파를. 이벤트 전파가 완료되면 B이로 설정됩니다 ready-state.

클래스를 추가하고 제거하는 것만으로 이것에 가까운 작업을 수행 할 수있는 방법을 알 수 있습니다. ready-state버튼 를 . 그러나 문제는 사용자가 변수를 설정할 수있는 것보다 빠르게 연속으로 두 번 버튼을 클릭 할 수 있으므로 일부 상황에서는 잠금 시도가 실패한다는 것입니다.

누구든지 JavaScript에서 실패하지 않는 잠금을 구현하는 방법을 알고 있습니까?


1
병렬 JS 실행 (예 : IE9)을 고려한 답변을 주시면 감사하겠습니다.
OrangeDog 2011 년

@smart 따라서 이전 이벤트의 전파가 완료 될 때까지 현재 이벤트 전파를 일시적으로 중지하려고합니다. 나는 그렇게 할 수 있다고 생각하지 않습니다. 이렇게 할 수 있습니다. 이벤트를 버리고 이전 이벤트가 전파를 완료하면 다른 이벤트를 발생시킵니다.
Šime Vidas 2011

@OrangeDog-IE9가 컴파일을 위해 전용 코어를 사용하려고한다고 들었습니다. 병렬 실행에 대해서는 아무 것도 없습니다. 소스를 인용 할 수 있습니까?
Brandon

1
@Brandon-그것은 당신이 제안한 것처럼 렌더러 자체와 병렬이 아닌 병렬을 의미 할 수 있습니다.
OrangeDog 2011 년

답변:


85

잠금은 스레드가없고 동시성 보호가 필요하지 않은 JS에서 의심스러운 아이디어입니다. 지연된 실행에 대한 호출을 결합하려고합니다. 내가 따르는 패턴은 콜백을 사용하는 것입니다. 이 같은:

var functionLock = false;
var functionCallbacks = [];
var lockingFunction = function (callback) {
    if (functionLock) {
        functionCallbacks.push(callback);
    } else {
        $.longRunning(function(response) {
             while(functionCallbacks.length){
                 var thisCallback = functionCallbacks.pop();
                 thisCallback(response);
             }
        });
    }
}

DOM 이벤트 리스너 또는 pubsub 솔루션을 사용하여이를 구현할 수도 있습니다.


18
"JS는 스레드가 없으며 동시성 보호가 필요하지 않습니다"라는 진술을 정당화하는 참조 문서를 제공해 주시겠습니까? 이에 대해 더 읽어보고 싶습니다.
smartcaveman 2011 년

2
+1-Node.js (JavaScript 웹 서버)가 JavaScript의 lone-thread 및 콜백 메커니즘을 활용하도록 구축 되었기 때문에 경쟁 조건이 없기 때문에 속성 잠금에 대해 걱정할 필요가 없다는 데 동의합니다.
Fenton 2011 년

4
$ .longRunning의 출처는 무엇입니까? (현재) jQuery에 없습니다.
Quantum7

3
functionLock을 언제 설정해야합니까?
Elton Garcia de Santana

11
"스레드가없고 동시성을 필요로하지 않는 JS"는 모호합니다. JS는 선점 형 동시성을 사용하지 않지만 협력 적 동시성 (콜백 또는 비동기 / 대기 기반)을 사용할 수 있습니다. 그것들을 사용할 때 확실히 경쟁 조건을 가질 수 있으며 뮤텍스 추상화를 사용하여 피할 수 있습니다.
ysdx

32

JavaScript는 예외 ( XMLHttpRequest onreadystatechange일부 Firefox 버전의 핸들러)가 거의 없는 이벤트 루프 동시 . 따라서이 경우 잠금에 대해 걱정할 필요가 없습니다.

JavaScript에는 "이벤트 루프"를 기반으로하는 동시성 모델이 있습니다. 이 모델은 C 또는 Java와 같은 다른 언어의 모델과는 상당히 다릅니다.

...

JavaScript 런타임에는 처리 할 메시지 목록 인 메시지 큐가 포함됩니다. 각 메시지에는 기능이 연결되어 있습니다. 스택이 비어 있으면 큐에서 메시지를 가져와 처리합니다.처리는 관련 함수를 호출하여 초기 스택 프레임을 만드는 것으로 구성됩니다. 스택이 다시 비워지면 메시지 처리가 종료됩니다.

...

각 메시지는 다른 메시지가 처리되기 전에 완전히 처리됩니다. 이것은 함수가 실행될 때마다 선점 될 수없고 다른 코드가 실행되기 전에 완전히 실행된다는 사실을 포함하여 프로그램에 대해 추론 할 때 좋은 속성을 제공합니다 (그리고 함수가 조작하는 데이터를 수정할 수 있음). 예를 들어, 함수가 스레드에서 실행되는 경우 언제든지 중지되어 다른 스레드에서 다른 코드를 실행할 수있는 C와 다릅니다.

이 모델의 단점은 메시지를 완료하는 데 너무 오래 걸리면 웹 애플리케이션이 클릭 또는 스크롤과 같은 사용자 상호 작용을 처리 할 수 ​​없다는 것입니다. 브라우저는 "스크립트를 실행하는 데 너무 오래 걸립니다"대화 상자로이를 완화합니다. 따라야 할 좋은 방법은 메시지 처리를 짧게 만들고 가능하면 하나의 메시지를 여러 메시지로 줄이는 것입니다.

이벤트 루프 동시성에 대한 추가 링크는 E를 참조하십시오.


그리고 자바 스크립트의 웹 작업자 (비 UI 스레드) 를 사용하면 각 개체 가 다른 작업자 (스레드) 또는 UI 스레드로 보내기 전에 복제 되고 개체는 다른 스레드에서 다른 인스턴스를 가지며 각 스레드는 이벤트 루프를 소유하고 마지막으로 Mike의 대답에 동의합니다. 유용한 답변입니다. 감사합니다 Mike.
Ehsan Mohammadi

11

나는 성공 뮤텍스 약속을했습니다 .

귀하의 경우 잠금이 필요하지 않을 수도 있다는 다른 답변에 동의합니다. 그러나 Javascript에서 잠금이 필요하지 않다는 것은 사실이 아닙니다. 동시성을 처리하지 않는 외부 리소스에 액세스 할 때는 상호 배타성이 필요합니다.


매우 필요한 일 감사합니다.
Dmitrij Polyanin

6

잠금은 다중 스레드 시스템에 필요한 개념입니다. 작업자 스레드를 사용하더라도 작업자간에 메시지가 값별로 전송되므로 잠금이 필요하지 않습니다.

버튼 사이에 세마포어 (플래 깅 시스템)를 설정해야한다고 생각합니다.


1
자바 스크립트로 구현 된 '세마포어 / 플래 깅 시스템'에 대한 예제 나 리소스가 있습니까?
smartcaveman 2011 년

4
PLenty 바로 여기에 있습니다. 예를 들어 stackoverflow.com/questions/4194346/…
James Westgate

James 귀하가 게시 한 링크에 세마포어 예제가 없습니다. 초당 하나의 요청 만 허용하므로 외부 서버에 대한 호출을 방지해야하므로 각 루프에 대한 요청을 건너 뛰지 않고 내 for next 루프 내에서 경과 시간이 경과 할 때까지 호출을 방지하는 플래그 지정 예제가 필요합니다.
Claus

안녕하세요 @Claus. 스택에 따라 두 가지가 마음에 퍼집니다. 속도 제한 플러그인을 지원하는 것처럼 보이는 Axios와 같은 라이브러리를 사용하거나 도메인을 기반으로 요청 속도를 제한하는 웹 워커를 만들 수 있습니다.
James Westgate

응답 해 주셔서 감사합니다. 처리가 끝날 때 setInterval과 함께 클릭 이벤트를 호출하여 해결했습니다. 간격을 1000 밀리 초로 설정 이제 요청에 대한 호스트 서버 제한을 ​​따르고 응답이 반환되기 전에 더 이상 Ajax 호출을 종료하지 않습니다.
Claus

2

이벤트를 마친 후 버튼을 비활성화하고 활성화하지 않는 이유는 무엇입니까?

<input type="button" id="xx" onclick="checkEnableSubmit('true');yourFunction();">

<script type="text/javascript">

function checkEnableSubmit(status) {  
  document.getElementById("xx").disabled = status;
}

function yourFunction(){

//add your functionality

checkEnableSubmit('false');
}

</script>

행복한 코딩 !!!


0

내 경우에 따르면 JoshRiver의 답변에 추가되었습니다.

var functionCallbacks = [];
    var functionLock = false;
    var getData = function (url, callback) {
                   if (functionLock) {
                        functionCallbacks.push(callback);
                   } else {
                       functionLock = true;
                       functionCallbacks.push(callback);
                        $.getJSON(url, function (data) {
                            while (functionCallbacks.length) {
                                var thisCallback = functionCallbacks.pop();
                                thisCallback(data);
                            }
                            functionLock = false;
                        });
                    }
                };

// Usage
getData("api/orders",function(data){
    barChart(data);
});
getData("api/orders",function(data){
  lineChart(data);
});

단 하나의 api 호출이 있으며이 두 함수는 동일한 결과를 사용합니다.


0

잠금은 여전히 ​​JS에서 사용됩니다. 내 경험상 나는 AJAX 호출을하는 요소를 클릭하는 스팸을 방지하기 위해 잠금을 사용하기 만하면되었다. AJAX 호출을 위해 설정된 로더가있는 경우이 작업은 필요하지 않습니다 (클릭 후 버튼 비활성화도 포함). 하지만 여기 어느 쪽이든 내가 잠금에 사용한 것입니다.

var LOCK_INDEX = [];
function LockCallback(key, action, manual) {
    if (LOCK_INDEX[key])
        return;
    LOCK_INDEX[key] = true;
    action(function () { delete LOCK_INDEX[key] });
    if (!manual)
        delete LOCK_INDEX[key];
}

용법:

수동 잠금 해제 (일반적으로 XHR 용)

LockCallback('someKey',(delCallback) => { 
    //do stuff
    delCallback(); //Unlock method
}, true)

자동 잠금 해제

LockCallback('someKey',() => { 
    //do stuff
})

0

다음은 폐쇄를 통해 구현 된 간단한 잠금 메커니즘입니다.

const createLock = () => {

    let lockStatus = false

    const release = () => {
        lockStatus = false
    }

    const acuire = () => {
        if (lockStatus == true)
            return false
        lockStatus = true
        return true
    }
    
    return {
        lockStatus: lockStatus, 
        acuire: acuire,
        release: release,
    }
}

lock = createLock() // create a lock
lock.acuire() // acuired a lock

if (lock.acuire()){
  console.log("Was able to acuire");
} else {
  console.log("Was not to acuire"); // This will execute
}

lock.release() // now the lock is released

if(lock.acuire()){
  console.log("Was able to acuire"); // This will execute
} else {
  console.log("Was not to acuire"); 
}

lock.release() // Hey don't forget to release

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.