다음 예에서 outerScopeVar
가 모든 경우에 정의되지 않은 이유는 무엇입니까?
이 모든 예에서 undefined
가 출력되는 이유는 무엇입니까? 해결책은 필요하지 않습니다. 왜 이런 일이 발생하는지 알고 싶습니다.
참고: JavaScript 비동기성에 대한 사양 질문입니다. 이 질문을 자유롭게 개선하고 커뮤니티가 동의할 수 있는 더 간단한 예를 추가하세요.
P粉9305342802023-10-14 16:59:42
Fabrício의 답변은 매우 정확합니다. 하지만 저는 비유를 통해 비동기성의 개념을 설명하는 데 초점을 맞춰 그의 답변을 좀 덜 기술적인 것으로 보완하고 싶습니다.
어제 제가 하고 있는 일을 위해 동료들로부터 정보를 얻어야 했어요. 나는 그에게 전화를 걸었습니다. 대화는 다음과 같습니다:
이 시점에서 나는 전화를 끊었습니다. 보고서를 완성하려면 Bob의 정보가 필요했기 때문에 보고서를 놓고 커피 한 잔을 마시러 간 다음 이메일을 몇 개 읽었습니다. 40분 후(Bob의 속도가 느림) Bob이 다시 전화를 걸어 필요한 정보를 제공했습니다. 이 시점에서는 필요한 정보를 모두 얻었으므로 보고서 작성을 계속합니다.
대화가 이런 식으로 흘러간다고 상상해보세요
저는 거기 앉아서 기다렸어요. 그리고 기다렸다. 그리고 기다렸다. 40분. 아무것도 하지 말고 기다리세요. 결국 Bob은 나에게 정보를 주었고 우리는 전화를 끊었고 나는 보고서를 마쳤습니다. 그러나 나는 40분의 생산성을 잃었습니다.
이것이 바로 우리 질문의 모든 예에서 일어나는 일입니다. 이미지 로드, 디스크에서 파일 로드, AJAX를 통한 페이지 요청은 모두 현대 컴퓨팅 환경에서 느린 작업입니다.
JavaScript를 사용하면 느린 작업이 완료될 때까지 기다리는 대신 느린 작업이 완료될 때 실행될 콜백 함수를 등록할 수 있습니다. 그러나 그동안 JavaScript는 다른 코드를 계속 실행합니다. JavaScript가 느린 작업이 완료되기를 기다리는 동안 다른 코드를 실행한다는 사실은 동작을 비동기로 만듭니다. JavaScript가 다른 코드를 실행하기 전에 작업이 완료될 때까지 기다리는 경우 이는 동기 동작이 됩니다.
으아아아위 코드에서는 JavaScript에 lolcat.png
를 로드하도록 요청하는데, 이는 lolcat.png
,这是一个sloooow 操作。一旦这个缓慢的操作完成,回调函数就会被执行,但与此同时,JavaScript 将继续处理下一行代码;即alert(outerScopeVar)
sloooow
alert(outerScopeVar)
를 계속 처리합니다.
未定义
;因为 alert()
그래서 이미지가 로드된 후가 아니라
alert(outerScopeVar)
代码移到回调函数中。因此,我们不再需要将 outerScopeVar
코드를 수정하려면
으아아아 함수로 지정된 콜백은 항상
보게 됩니다. 이는 JavaScript에서 일부 코드를 정의한 다음 나중에 실행하는 유일한* 방법이기 때문입니다.
function() { /* Do Something */ }
따라서 모든 예제에서 는 콜백입니다. 모든
* 기술적으로는 eval()
,但是eval()
악을 이 목적으로 사용할 수도 있습니다
현재 이와 유사한 코드가 있을 수 있습니다.
으아악하지만 이제 우리는 알고 있습니다 返回outerScopeVar
会立即发生;在 onload
回调函数更新变量之前。这会导致 getWidthOfImage()
返回 undefined
,并发出警报 undefined
.
이 문제를 해결하려면 getWidthOfImage()
호출하는 함수가 콜백을 등록한 다음 해당 콜백 내로 너비 경고를 이동하도록 허용해야 합니다.
으아악
). width
P粉1788942352023-10-14 10:02:51
한 단어로 대답: 비동시성.
이 주제는 Stack Overflow에서 최소 수천 번 반복되었습니다. 먼저 매우 유용한 리소스를 알려드리고 싶습니다.
@Felix Kling의 "비동기 호출에서 응답을 반환하는 방법은 무엇입니까?"에 대한 답변입니다. 동기 및 비동기 프로세스를 설명하는 그의 훌륭한 답변과 "코드 재구성" 섹션을 참조하세요.
@Benjamin Gruenbaum도 동일한 스레드 내에서 비동기성을 설명하기 위해 많은 노력을 기울였습니다.
"fs.readFile에서 데이터 가져오기"에 대한 @Matt Esch의 답변 또한 간단한 방법으로 비동기성을 아주 잘 설명합니다.
먼저 일반적인 행동을 추적해 보겠습니다. 모든 예에서 outerScopeVar
는 함수 내에서 수정됩니다. 이 함수는 분명히 즉시 실행되지 않으며 매개변수로 할당되거나 전달됩니다. 이것을 콜백이라고 부릅니다.
이제 질문은 이 콜백이 언제 호출되는가입니다.
상황에 따라 다릅니다. 몇 가지 일반적인 행동을 다시 추적해 보겠습니다.
img.onload
언제든지 이라고 할 수 있습니다. (만약) 이미지가 성공적으로 로드되었습니다. setTimeout
은 지연이 만료되고 clearTimeout
에 의해 시간 초과가 취소되지 않은 후 setTimeout
可能会在延迟到期且超时尚未被 clearTimeout
取消后在将来的某个时间被调用。注意:即使使用 0
향후 언젠가0
을 지연으로 사용하는 경우에도 모든 브라우저에는 최소 시간 초과 지연(HTML5 사양에서 4밀리초로 지정됨)에 대한 상한이 있습니다. $.post
jQuery fs.readFile
Node.js' 는 파일을 성공적으로 읽었거나 오류가 발생하면 미래에모든 경우에 미래에 언젠가 실행될 수 있는 콜백이 있습니다. 이 "미래의 언젠가"를 우리는 비동기 흐름
이라고 부릅니다.비동기 실행은 동기 프로세스에서 푸시됩니다. 즉, 동기 코드 스택이 실행되는 동안 비동기 코드는 영원히
실행됩니다. 이것이 JavaScript의 단일 스레드입니다. 로 간주됩니다.즉, 손으로 그린 빨간색 모양으로 강조 표시된 비동기 코드는 해당 코드 블록에 남아 있는 모든 동기 코드가 실행된 후에만 실행될 수 있습니다.
간단히 말하면 콜백 함수는 동기적으로 생성되지만 비동기적으로 실행됩니다. 비동기 함수가 실행되었다는 사실을 알기 전까지는 비동기 함수의 실행에 의존할 수 없습니다. 이를 어떻게 수행합니까? 🎜
정말 간단해요. 비동기 함수 실행에 의존하는 로직은 해당 비동기 함수 내에서 시작/호출되어야 합니다. 예를 들어 콜백 함수 내에서 alert
和 console.log
를 이동하면 해당 시점에 결과를 사용할 수 있으므로 예상한 결과가 출력됩니다.
비동기 함수의 결과에 대해 더 많은 작업을 수행해야 하거나 비동기 함수가 호출되는 위치에 따라 결과에 대해 다른 작업을 수행해야 하는 경우가 많습니다. 좀 더 복잡한 예를 살펴보겠습니다.
으아악참고: 저는 일반 비동기 함수로 임의 지연과 함께 setTimeout
를 사용하고 있습니다. 동일한 예가 Ajax, readFile, onload 및 기타 비동기 흐름에 적용됩니다.
이 예제에는 분명히 다른 예제와 동일한 문제가 있습니다. 비동기 함수가 실행될 때까지 기다리지 않습니다.
자체 콜백 시스템을 구현하여 이 문제를 해결해 보겠습니다. 먼저, 이 경우에는 전혀 쓸모가 없는 추악한 outerScopeVar
을 제거합니다. 그런 다음 함수 인수인 콜백을 허용하는 매개변수를 추가합니다. 비동기 작업이 완료되면 이 콜백을 호출하고 결과를 전달합니다. 구현 (댓글을 순서대로 읽어주세요):
위 예의 코드 조각: