함수 내에서 수정한 후에도 변수가 변경되지 않은 상태로 유지됩니까? - 비동기 코드 참조
P粉403804844
P粉403804844 2023-08-28 11:46:28
0
2
444
<p>鉴于以下示例,为什么 <code>outerScopeVar</code> 거기에 어떤 정보가 있나요?</p> <pre class="brush:php;toolbar:false;">var externalScopeVar; var img = document.createElement('img'); img.onload = 함수() { externalScopeVar = this.width; }; img.src = 'lolcat.png'; Alert(outerScopeVar);</pre> <pre class="brush:php;toolbar:false;">var externalScopeVar; setTimeout(함수() { externalScopeVar = '안녕하세요 비동기 세계!'; }, 0); Alert(outerScopeVar);</pre> <pre class="brush:php;toolbar:false;">// 일부 jQuery를 사용한 예 var externalScopeVar; $.post('loldog', function(response) { externalScopeVar = 응답; }); Alert(outerScopeVar);</pre> <pre class="brush:php;toolbar:false;">// Node.js 예 var externalScopeVar; fs.readFile('./catdog.html', function(err, data) { externalScopeVar = 데이터; }); console.log(outerScopeVar);</pre> <pre class="brush:php;toolbar:false;">// 약속 있음 var externalScopeVar; myPromise.then(함수(응답) externalScopeVar = 응답; }); console.log(outerScopeVar);</pre> <pre class="brush:php;toolbar:false;">// 관찰 가능 항목 포함 var externalScopeVar; myObservable.subscribe(함수 (값) { externalScopeVar = 값; }); console.log(outerScopeVar);</pre> <pre class="brush:php;toolbar:false;">// 위치정보 API var externalScopeVar; navigator.geolocation.getCurrentPosition(함수 (pos) { 외부 범위Var = pos; }); console.log(outerScopeVar);</pre> <p>为什么에서 <code>정의되지 않음</code> ?我不需要解决方法,我想知道<strong>为什么</strong>发生这种情况。</p> <시간 /> <인용문> <p><strong>注意:</strong>这是一个关于 JavaScript는 异步性规范问题입니다.示例。</p> </blockquote><p><br /></p>
P粉403804844
P粉403804844

모든 응답(2)
P粉064448449

Fabrício의 답변은 매우 정확합니다. 하지만 저는 비유를 통해 비동기성의 개념을 설명하는 데 초점을 맞춰 그의 답변을 좀 덜 기술적인 것으로 보완하고 싶습니다.


비유...

어제 제가 하고 있는 일을 위해 동료들로부터 정보를 얻어야 했어요. 나는 그에게 전화를 걸었습니다. 대화는 다음과 같습니다:

이 시점에서 나는 전화를 끊었다. 보고서를 완성하려면 Bob의 정보가 필요했기 때문에 보고서를 놓고 커피 한 잔을 마시고 이메일을 몇 개 읽었습니다. 40분 후(Bob의 속도가 느림) Bob이 다시 전화를 걸어 필요한 정보를 제공했습니다. 이 시점에서는 필요한 정보를 모두 얻었으므로 보고서 작성 작업을 계속합니다.


대화가 이렇게 흘러간다고 상상해보세요

저는 거기 앉아서 기다렸어요. 그리고 기다렸다. 그리고 기다렸다. 40분. 아무것도 하지 말고 기다리세요. 결국 Bob은 나에게 정보를 주었고 우리는 전화를 끊었고 나는 보고서를 마쳤습니다. 그러나 나는 40분의 생산성을 잃었습니다.


이것은 비동기식 대 동기식 동작입니다

이것이 바로 우리 질문의 모든 예에서 일어나는 일입니다. 이미지 로드, 디스크에서 파일 로드, AJAX를 통한 페이지 요청은 모두 현대 컴퓨팅 환경에서 느린 작업입니다.

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

으아악

위 코드에서는 JavaScript에 lolcat.png를 로드하도록 요청하는데, 이는 lolcat.png,这是一个sloooow 操作。一旦这个缓慢的操作完成,回调函数就会被执行,但与此同时,JavaScript 将继续处理下一行代码;即alert(outerScopeVar)sloooow

작업입니다. 이 느린 작업이 완료되면 콜백 함수가 실행되지만 그 동안 JavaScript는 다음 코드 줄인 alert(outerScopeVar)를 계속 처리합니다.

未定义;因为 alert()그래서 이미지가 로드된 후가 아니라

즉시 처리된다는 경고가 표시됩니다.

alert(outerScopeVar) 代码移到回调函数中。因此,我们不再需要将 outerScopeVar코드를 수정하려면

변수를 전역 변수로 선언하기만 하면 됩니다.

으아악 함수로 지정된 콜백은 항상

보게 됩니다. 이는 JavaScript에서 일부 코드를 정의한 다음 나중에 실행하는 유일한* 방법이기 때문입니다.

function() { /* Do Something */ }따라서 모든 예제에서 는 콜백입니다. 모든

예제를 수정하려면 액션 응답이 필요한 코드를 그곳으로 옮기기만 하면 됩니다! 🎜

* 기술적으로는 eval(),但是eval()악을 이 목적으로 사용할 수도 있습니다


발신자를 대기 상태로 만드는 방법은 무엇입니까?

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

으아악

하지만 이제 우리는 알고 있습니다 返回outerScopeVar会立即发生;在 onload 回调函数更新变量之前。这会导致 getWidthOfImage() 返回 undefined,并发出警报 undefined.

이 문제를 해결하려면 getWidthOfImage() 호출하는 함수가 콜백을 등록한 다음 해당 콜백 내로 너비 경고를 이동하도록 허용해야 합니다. 으아악

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

). width

P粉191610580

한 단어로 대답: 비동시성.

머리말

이 주제는 Stack Overflow에서 최소 수천 번 반복되었습니다. 먼저 매우 유용한 리소스를 알려드리고 싶습니다.


현재 질문에 대한 답변

먼저 일반적인 행동을 추적해 보겠습니다. 모든 예에서 outerScopeVar 함수 내에서 수정됩니다. 이 함수는 분명히 즉시 실행되지 않으며 매개변수로 할당되거나 전달됩니다. 이것을 콜백이라고 부릅니다.

이제 질문은 이 콜백이 언제 호출되는가입니다.

상황에 따라 다릅니다. 몇 가지 일반적인 행동을 다시 추적해 보겠습니다.

  • img.onload 언제든지 이라고 할 수 있습니다. (만약) 이미지가 성공적으로 로드되었습니다.
  • setTimeout은 지연이 만료되고 clearTimeout에 의해 시간 초과가 취소되지 않은 후 setTimeout 可能会在延迟到期且超时尚未被 clearTimeout 取消后在将来的某个时间被调用。注意:即使使用 0향후 언젠가
  • 호출될 수 있습니다. 참고: 0을 지연으로 사용하는 경우에도 모든 브라우저에는 최소 시간 초과 지연(HTML5 사양에서 4밀리초로 지정됨)에 대한 상한이 있습니다.
  • Ajax 요청이 성공적으로 완료되면 향후 $.post jQuery
  • 의 콜백이 호출될 수 있습니다.
  • fs.readFileNode.js' 는 파일을 성공적으로 읽었거나 오류가 발생하면 미래에
  • 호출될 수 있습니다.

모든 경우에 미래에 언젠가 실행될 수 있는 콜백이 있습니다. 이 "미래의 언젠가"를 우리는 비동기 흐름

이라고 부릅니다.

비동기 실행은 동기 프로세스에서 푸시됩니다. 즉, 동기 코드 스택이 실행되는 동안 비동기 코드는 영원히

실행됩니다. 이것이 JavaScript의 단일 스레드입니다.

좀 더 구체적으로 말하자면, JS 엔진이 여러 동기 코드를 실행하지 않고 유휴 상태일 때 비동기 콜백(예: 시간 초과, 수신된 네트워크 응답)을 트리거할 수 있는 이벤트를 폴링하고 차례로 실행합니다. 이는 이벤트 루프

로 간주됩니다.

즉, 손으로 그린 ​​빨간색 모양으로 강조 표시된 비동기 코드는 해당 코드 블록에 남아 있는 모든 동기 코드가 실행된 후에만 실행될 수 있습니다.

간단히 말하면 콜백 함수는 동기적으로 생성되지만 비동기적으로 실행됩니다. 비동기 함수가 실행되었다는 사실을 알기 전까지는 비동기 함수의 실행에 의존할 수 없습니다. 이를 어떻게 수행합니까? 🎜

정말 간단해요. 비동기 함수 실행에 의존하는 로직은 해당 비동기 함수 내에서 시작/호출되어야 합니다. 예를 들어 콜백 함수 내에서 alertconsole.log를 이동하면 해당 시점에 결과를 사용할 수 있으므로 예상한 결과가 출력됩니다.

자신만의 콜백 로직을 구현하세요

비동기 함수의 결과에 대해 더 많은 작업을 수행해야 하거나 비동기 함수가 호출되는 위치에 따라 결과에 대해 다른 작업을 수행해야 하는 경우가 많습니다. 좀 더 복잡한 예를 살펴보겠습니다.

으아악

참고: 저는 일반 비동기 함수로 임의 지연과 함께 setTimeout를 사용하고 있습니다. 동일한 예가 Ajax, readFile, onload 및 기타 비동기 흐름에 적용됩니다.

이 예제에는 분명히 다른 예제와 동일한 문제가 있습니다. 비동기 함수가 실행될 때까지 기다리지 않습니다.

자체 콜백 시스템을 구현하여 이 문제를 해결해 보겠습니다. 먼저, 이 경우에는 전혀 쓸모가 없는 추악한 outerScopeVar 을 제거합니다. 그런 다음 함수 인수인 콜백을 허용하는 매개변수를 추가합니다. 비동기 작업이 완료되면 이 콜백을 호출하고 결과를 전달합니다. 구현 (댓글을 순서대로 읽어주세요):

으아악

위 예의 코드 조각:

으아악
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿