[javascript] 변수를 함수 내부에서 수정 한 후에 변수가 변경되지 않는 이유는 무엇입니까? - 비동기 코드 참조


Answers

Fabrício의 답변이 자리하고 있습니다. 그러나 비동기의 개념을 설명하는 데 도움이되는 비유에 초점을 둔 덜 기술적 인 것으로 답변을 보완하고자했습니다 .

유추 ...

어제, 내가 한 일은 동료로부터 정보를 요구했다. 나는 그를 울렸다. 대화가 어떻게 진행되었는지 알려주세요.

: 안녕, 밥. 지난주에 우리가 바를 어떻게 푸는지 알아야 해. Jim은 그것에 대한 보고서를 원합니다. 그리고 당신은 그것에 대해 자세히 알고있는 유일한 사람입니다.

확실해,하지만 30 분 정도 걸릴거야?

: 대단한 Bob이에요. 정보를 얻었 으면 전화를 돌려줘!

이 시점에서 나는 전화를 끊었다. 보고서 작성을 위해 Bob의 정보가 필요했기 때문에 보고서를 남겨두고 대신 커피를 사러갔습니다. 그런 다음 이메일을 받았습니다. 40 분 후 (밥은 천천히) 밥은 전화를 걸어서 필요한 정보를 나에게주었습니다. 이 시점에서 필자는 필자가 필요로하는 모든 정보를 얻었으므로 보고서를 작성하여 작업을 재개했습니다.

대화가 이렇게 바뀌 었다고 상상해보십시오.

: 안녕, 밥. 지난주에 우리가 바를 어떻게 푸는지 알아야 해. Jim은 그것에 대한 보고서를 원하고, 당신은 그것에 대해 자세히 알고있는 유일한 사람입니다.

확실해,하지만 30 분 정도 걸릴거야?

: 대단한 Bob이에요. 기다릴게.

그리고 나는 거기에 앉아 기다렸다. 그리고 기다렸다. 그리고 기다렸다. 40 분 동안. 아무것도하지 않고 기다리는 것. 결국 밥은 정보를 주었고 끊어서 보고서를 완성했습니다. 하지만 40 분의 생산성을 잃어 버렸습니다.

비동기 대 동기 동작입니다.

이것은 정확히 우리의 질문에있는 모든 예에서 일어나는 일입니다. 이미지로드, 디스크에서 파일로드 및 AJAX를 통한 페이지 요청은 모두 최신 컴퓨팅의 맥락에서 느린 작업입니다.

이러한 느린 작업이 완료 되기를 기다리는 대신 JavaScript를 사용하면 느린 작업이 완료 될 때 실행될 콜백 함수를 등록 할 수 있습니다. 그러나 그 동안 JavaScript는 다른 코드를 계속 실행합니다. 느린 작업이 완료 될 때까지 기다리는 동안 JavaScript가 다른 코드 를 실행한다는 사실은 비동기 동작을 만듭니다. JavaScript가 다른 코드를 실행하기 전에 작업이 완료되기를 기다렸다면 동기 동작이었을 것입니다.

var outerScopeVar;    
var img = document.createElement('img');

// Here we register the callback function.
img.onload = function() {
    // Code within this function will be executed once the image has loaded.
    outerScopeVar = this.width;
};

// But, while the image is loading, JavaScript continues executing, and
// processes the following lines of JavaScript.
img.src = 'lolcat.png';
alert(outerScopeVar);

위의 코드에서 우리는 자바 스크립트에 lolcat.png 를로드 lolcat.png 요청하고 lolcat.png , 이것은 슬 루우 연산입니다. 이 느린 작업이 완료되면 콜백 함수가 실행되지만 JavaScript는 다음 코드 행을 계속 처리합니다. ie alert(outerScopeVar) 입니다.

이것이 우리가 알 수없는 경고를 보는 이유입니다. 왜냐하면 alert() 은 이미지가로드 된 후에가 아니라 즉시 처리되기 때문입니다.

코드를 수정하려면 alert(outerScopeVar) 코드 콜백 함수 alert(outerScopeVar) 됩니다. 결과적으로 전역 변수로 선언 된 outerScopeVar 변수가 더 이상 필요하지 않습니다.

var img = document.createElement('img');

img.onload = function() {
    var localScopeVar = this.width;
    alert(localScopeVar);
};

img.src = 'lolcat.png';

콜백은 함수로 지정됩니다. JavaScript가 일부 코드를 정의하는 유일한 방법이기 때문에 콜백이 나중에 지정 될 때까지 실행되지 않습니다.

따라서 모든 예제에서 function() { /* Do something */ } 이 콜백입니다. 모든 예제를 수정하려면, 우리가해야 할 일은 거기에 작업의 응답을 필요로 코드를 이동하는 것입니다!

기술적으로 당신은 eval() 을 사용할 수도 있지만,이 목적을 위해 eval() 은 악 합니다.

내 발신자를 대기 상태로 유지하려면 어떻게해야합니까?

현재 이와 유사한 코드가있을 수 있습니다.

function getWidthOfImage(src) {
    var outerScopeVar;

    var img = document.createElement('img');
    img.onload = function() {
        outerScopeVar = this.width;
    };
    img.src = src;
    return outerScopeVar;
}

var width = getWidthOfImage('lolcat.png');
alert(width);

그러나 이제 return outerScopeVar 즉시 발생한다는 것을 return outerScopeVar 습니다. onload 콜백 함수가 변수를 업데이트하기 전에. 이로 인해 getWidthOfImage() undefined 반환하고 undefined 는 경고를받습니다.

이 문제를 해결하려면 getWidthOfImage() 를 호출하는 함수가 콜백을 등록하도록 허용 한 다음 해당 폭의 경고를 해당 콜백 내에 있도록 이동해야합니다.

function getWidthOfImage(src, cb) {     
    var img = document.createElement('img');
    img.onload = function() {
        cb(this.width);
    };
    img.src = src;
}

getWidthOfImage('lolcat.png', function (width) {
    alert(width);
});

... 전과 마찬가지로 전역 변수 (이 경우 width )를 제거 할 수있었습니다.

Question

다음 예제를 통해, outerScopeVar 이 모든 경우에 정의되지 않은 이유는 무엇입니까?

var outerScopeVar;

var img = document.createElement('img');
img.onload = function() {
    outerScopeVar = this.width;
};
img.src = 'lolcat.png';
alert(outerScopeVar);

var outerScopeVar;
setTimeout(function() {
    outerScopeVar = 'Hello Asynchronous World!';
}, 0);
alert(outerScopeVar);

// Example using some jQuery
var outerScopeVar;
$.post('loldog', function(response) {
    outerScopeVar = response;
});
alert(outerScopeVar);

// Node.js example
var outerScopeVar;
fs.readFile('./catdog.html', function(err, data) {
    outerScopeVar = data;
});
console.log(outerScopeVar);

// with promises
var outerScopeVar;
myPromise.then(function (response) {
    outerScopeVar = response;
});
console.log(outerScopeVar);

// geolocation API
var outerScopeVar;
navigator.geolocation.getCurrentPosition(function (pos) {
    outerScopeVar = pos;
});
console.log(outerScopeVar);

이 모든 예제에서 출력이 undefined 이유는 무엇입니까? 해결 방법이 필요하지 않은 이유 가 무엇 인지 알고 싶습니다.

참고 : 이것은 JavaScript 비동기에 대한 표준적인 질문입니다. 이 질문을 향상시키고 커뮤니티가 식별 할 수있는보다 간단한 예제를 추가하십시오.




이러한 모든 시나리오에서 outerScopeVar 가 수정되거나 값을 비동기 적으로 할당하거나 나중에 실행 (대기 또는 일부 이벤트 발생 대기)하여 현재 실행이 대기하지 않습니다. 이러한 경우 모두 현재 실행 흐름의 결과 outerScopeVar = undefined

각 예제 (비동기 적으로 호출되거나 일부 이벤트가 발생하도록 지연된 부분을 표시)에 대해 설명합시다.

1.

여기에 우리는 특정 이벤트에서 실행될 eventlistner를 등록합니다. 여기에 이미지로드가 있습니다. 다음 라인과 연속 된 현재 실행 img.src = 'lolcat.png';alert(outerScopeVar); 그 동안 이벤트가 발생하지 않을 수도 있습니다. ie, funtion img.onload 는 참조 된 이미지가 비동기 적으로로드 img.onload 때까지 대기합니다. 이것은 모든 후속 예제에서 발생합니다. 이벤트는 다를 수 있습니다.

2.

여기서 timeout 이벤트는 지정된 시간 후에 처리기를 호출하는 역할을합니다. 여기에 0 이지만 여전히 비동기 이벤트가 등록되므로 실행을 위해 Event Queue 의 마지막 위치에 추가됩니다. 이는 보장 된 지연을 만듭니다.

삼.

이번에는 아약스 콜백입니다.

4.

노드는 비동기 코딩의 왕으로서 고려 될 수 있습니다. 여기 표시된 함수는 지정된 파일을 읽은 후 실행될 콜백 핸들러로 등록됩니다.

5.

명백한 약속 (미래에 어떤 일이 이루어질 것입니다)은 비동기입니다. JavaScript에서 지연, 약속 및 미래의 차이점무엇입니까?를 참조하십시오 .

https://www.quora.com/Whats-the-difference-between-a-promise-and-a-callback-in-Javascript




분명한 사실을 outerScopeVar 위해 컵은 outerScopeVar 나타 outerScopeVar .

비동기 함수처럼 ...




Links