순차 Javascript 실행을 강제하는 방법은 무엇입니까?
나는 클래스, 이벤트 핸들러 및 콜백과 관련된 다소 복잡한 답변을 찾았습니다 (나에게 다소 멍청한 접근 방식으로 보입니다). 콜백이 유용 할 수 있다고 생각하지만 가장 간단한 컨텍스트에서는 적용 할 수없는 것 같습니다. 이 예를 참조하십시오.
<html>
<head>
<script type="text/javascript">
function myfunction() {
longfunctionfirst();
shortfunctionsecond();
}
function longfunctionfirst() {
setTimeout('alert("first function finished");',3000);
}
function shortfunctionsecond() {
setTimeout('alert("second function finished");',200);
}
</script>
</head>
<body>
<a href="#" onclick="javascript:myfunction();return false;">Call my function</a>
</body>
</html>
여기서 두 번째 기능은 첫 번째 기능보다 먼저 완료됩니다. 첫 번째 함수가 완료 될 때까지 두 번째 함수가 실행을 지연하도록하는 가장 간단한 방법 (또는 하나가 있습니까?)은 무엇입니까?
---편집하다---
그래서 그것은 쓰레기의 예 였지만 David Hedlund 덕분에이 새로운 예에서 이것이 실제로 동기 적이라는 것을 알았습니다 (테스트 프로세스에서 내 브라우저가 충돌하는 것과 함께!).
<html>
<head>
<script type="text/javascript">
function myfunction() {
longfunctionfirst();
shortfunctionsecond();
}
function longfunctionfirst() {
var j = 10000;
for (var i=0; i<j; i++) {
document.body.innerHTML += i;
}
alert("first function finished");
}
function shortfunctionsecond() {
var j = 10;
for (var i=0; i<j; i++) {
document.body.innerHTML += i;
}
alert("second function finished");
}
</script>
</head>
<body>
<a href="#" onclick="javascript:myfunction();return false;">Call my function</a>
</body>
</html>
내 실제 문제는 jQuery와 IE와 관련이 있었기 때문에 내가 직접 얻을 수 없다면 그것에 대해 별도의 질문을 게시해야 할 것입니다!
글쎄,, setTimeout
그 정의에 따라 스레드를 유지하지 않습니다. 그렇게된다면 기다리는 시간 동안 전체 UI가 정지되기 때문입니다. 당신이 정말로 사용해야하는 경우 setTimeout
에, 당신은 콜백 함수를 사용한다 :
function myfunction() {
longfunctionfirst(shortfunctionsecond);
}
function longfunctionfirst(callback) {
setTimeout(function() {
alert('first function finished');
if(typeof callback == 'function')
callback();
}, 3000);
};
function shortfunctionsecond() {
setTimeout('alert("second function finished");', 200);
};
를 사용 하지 않고setTimeout
매우 오랫동안 실행되는 함수를 가지고 있고 setTimeout
이를 시뮬레이션하는 데 사용하는 경우 함수 는 실제로 동기식이며이 문제는 전혀 발생하지 않습니다. 그러나 AJAX 요청은 비동기 적이며 setTimeout
완료 될 때까지 UI 스레드를 유지하지 않습니다. AJAX를 사용하면에서와 마찬가지로 setTimeout
콜백으로 작업해야합니다.
나는 깨끗한 해결책이라고 생각하는 것을 찾는 데 오랜 시간이 걸렸기 때문에이 질문으로 돌아 왔습니다. 내가 아는 자바 스크립트 순차적 실행을 강제하는 유일한 방법은 약속을 사용하는 것입니다. Promises / A 및 Promises / A + 에 약속에 대한 완전한 설명이 있습니다.
내가 아는 약속을 구현하는 유일한 라이브러리는 jquery이므로 jquery promise를 사용하여 질문을 해결하는 방법은 다음과 같습니다.
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
function myfunction()
{
promise = longfunctionfirst().then(shortfunctionsecond);
}
function longfunctionfirst()
{
d = new $.Deferred();
setTimeout('alert("first function finished");d.resolve()',3000);
return d.promise()
}
function shortfunctionsecond()
{
d = new $.Deferred();
setTimeout('alert("second function finished");d.resolve()',200);
return d.promise()
}
</script>
</head>
<body>
<a href="#" onclick="javascript:myfunction();return false;">Call my function</a>
</body>
</html>
promise를 구현하고 .then () 함수를 연결하면 두 번째 함수가 첫 번째 함수가 실행 된 후에 만 실행되도록 보장합니다. 다음을 시작하라는 신호를 제공하는 longfunctionfirst ()의 명령 d.resolve ()입니다. 함수.
기술적으로 shortfunctionsecond ()는 지연을 생성하고 약속을 반환 할 필요가 없습니다.하지만 저는 약속과 사랑에 빠졌고 모든 것을 약속으로 구현하는 경향이 있습니다.
저는 프로그래밍에 익숙하고 최근에 제 열정으로 돌아 왔고이 객체 지향, 이벤트 중심의 밝은 새로운 세계에 맞추기 위해 고군분투하고 있습니다. Javascript의 비 순차적 동작의 이점을 확인하는 동안 실제로 얻을 수있는 시간이 있습니다. 단순성과 재사용 성의 방식으로. 제가 작업 한 간단한 예는 사진 (자바 스크립트, HTML, phonegap 등으로 프로그래밍 된 휴대폰)을 찍고 크기를 조정 한 다음 웹 사이트에 업로드하는 것입니다. 이상적인 순서는 다음과 같습니다.
- 사진을 찍다
- img 요소에 사진로드
- 그림 크기 조정 (Pixastic 사용)
- 웹 사이트에 업로드
- 사용자에게 성공 실패 알림
이 모든 단계가 완료되었을 때 다음 단계로 제어를 되 돌리는 각 단계가 있으면 매우 간단한 순차적 프로그램이 될 수 있지만 실제로는 다음과 같습니다.
- 사진 찍기는 비동기이므로 프로그램은 존재하기 전에 img 요소에로드하려고합니다.
- 사진로드는 비동기이므로 이미지가 완전히로드되기 전에 크기 조정 그림이 시작됩니다.
- 크기 조정은 비동기이므로 사진의 크기가 완전히 조정되기 전에 웹 사이트에 업로드가 시작됩니다.
- 웹 사이트에 업로드하는 것은 asyn이므로 사진이 완전히 업로드되기 전에 프로그램이 계속됩니다.
그리고 5 단계 중 btw 4에는 콜백 함수가 포함됩니다.
따라서 내 솔루션은 이전 단계의 각 단계를 중첩하고 .onload 및 기타 유사한 전략을 사용하는 것입니다. 다음과 같이 보입니다.
takeAPhoto(takeaphotocallback(photo) {
photo.onload = function () {
resizePhoto(photo, resizePhotoCallback(photo) {
uploadPhoto(photo, uploadPhotoCallback(status) {
informUserOnOutcome();
});
});
};
loadPhoto(photo);
});
(나는 내가 코드를 가져 오는 실수를 너무 많이하지 않았 으면 좋겠다. 진짜가 너무 산만하다는 것이 필수적이다)
이것은 비동기가 좋지 않고 동기화가 좋은 완벽한 예라고 생각합니다. 왜냐하면 Ui 이벤트 처리와 달리 다음이 실행되기 전에 각 단계를 완료해야하는데 코드는 러시아 인형 구조이므로 혼란스럽고 읽을 수 없습니다. 코드 재사용 성은 모든 중첩으로 인해 달성하기 어렵습니다. 각 컨테이너에 차례로 전달하거나 사악한 전역 변수를 사용하지 않고 필요한 모든 매개 변수를 내부 함수로 가져 오기가 어렵습니다. 그리고 그 결과가 좋았을 것입니다. 이 코드는 반환 코드를 제공하지만 반환 코드를 사용할 수 있기 훨씬 전에 첫 번째 컨테이너가 완료됩니다.
이제 Tom의 초기 질문으로 돌아가려면 Let say C와 멍청한 전자 보드를 사용하여 15 년 전에 매우 간단한 프로그램이었던 스마트하고 읽기 쉽고 재사용하기 쉬운 솔루션은 무엇일까요?
요구 사항은 사실 너무 간단해서 Javsascript와 최신 프로그래밍에 대한 근본적인 이해를 놓치고 있어야한다는 인상을 받았습니다. 확실히 기술은 생산성을 높이기위한 것입니다.
양해 해 주셔서 감사합니다.
Raymond the Dinosaur ;-)
자바 스크립트에서는 코드를 기다릴 방법이 없습니다. 나는이 문제가 있었고 내가 한 방식은 서버에 대한 동기 SJAX 호출을 수행하는 것이었고 서버는 실제로 절전 모드를 실행하거나 반환하기 전에 일부 활동을 수행하고 전체 시간 동안 js가 기다립니다.
예 : Sync AJAX : http://www.hunlock.com/blogs/Snippets:_Synchronous_AJAX
귀하의 예에서 첫 번째 함수는 두 번째 함수가 시작되기 전에 실제로 완료됩니다. setTimeout은 시간 제한에 도달 할 때까지 함수 실행을 유지하지 않으며, 단순히 백그라운드에서 타이머를 시작하고 지정된 시간 후에 경고 문을 실행합니다.
JavaScript에서 "잠자기"를 수행하는 기본 방법은 없습니다. 시간을 확인하는 루프를 작성할 수 있지만 클라이언트에 많은 부담을줍니다. emacsian이 설명했듯이 동기식 AJAX 호출을 수행 할 수도 있지만 서버에 추가로드가 발생합니다. 가장 좋은 방법은 실제로 이것을 피하는 것입니다. setTimeout의 작동 방식을 이해하면 대부분의 경우에 충분히 간단합니다.
콜백 방식을 시도했지만 작동하지 못했습니다. 이해해야 할 것은 실행이 아니지만 값이 여전히 원자 적이라는 것입니다. 예를 들면 :
alert('1');
<---이 두 기능은 동시에 실행됩니다.
alert('2');
<---이 두 기능은 동시에 실행됩니다.
하지만 이렇게하면 실행 순서를 알 수 있습니다.
loop=2;
total=0;
for(i=0;i<loop;i++) {
total+=1;
if(total == loop)
alert('2');
else
alert('1');
}
나는 같은 문제가 있었고 이것이 내 해결책입니다.
var functionsToCall = new Array();
function f1() {
$.ajax({
type:"POST",
url: "/some/url",
success: function(data) {
doSomethingWith(data);
//When done, call the next function..
callAFunction("parameter");
}
});
}
function f2() {
/*...*/
callAFunction("parameter2");
}
function f3() {
/*...*/
callAFunction("parameter3");
}
function f4() {
/*...*/
callAFunction("parameter4");
}
function f5() {
/*...*/
callAFunction("parameter5");
}
function f6() {
/*...*/
callAFunction("parameter6");
}
function f7() {
/*...*/
callAFunction("parameter7");
}
function f8() {
/*...*/
callAFunction("parameter8");
}
function f9() {
/*...*/
callAFunction("parameter9");
}
function callAllFunctionsSy(params) {
functionsToCall.push(f1);
functionsToCall.push(f2);
functionsToCall.push(f3);
functionsToCall.push(f4);
functionsToCall.push(f5);
functionsToCall.push(f6);
functionsToCall.push(f7);
functionsToCall.push(f8);
functionsToCall.push(f9);
functionsToCall.reverse();
callAFunction(params);
}
function callAFunction(params) {
if (functionsToCall.length > 0) {
var f=functionsToCall.pop();
f(params);
}
}
그렇지 순수 자바 스크립트를 사용하여 주장하는 경우에 순차적 코드를 만들 수 는 LiveScript을 그리고 그것은 꽤 좋은 보인다 . 이 예를 살펴볼 수 있습니다 .
# application
do
i = 3
console.log td!, "start"
<- :lo(op) ->
console.log td!, "hi #{i}"
i--
<- wait-for \something
if i is 0
return op! # break
lo(op)
<- sleep 1500ms
<- :lo(op) ->
console.log td!, "hello #{i}"
i++
if i is 3
return op! # break
<- sleep 1000ms
lo(op)
<- sleep 0
console.log td!, "heyy"
do
a = 8
<- :lo(op) ->
console.log td!, "this runs in parallel!", a
a--
go \something
if a is 0
return op! # break
<- sleep 500ms
lo(op)
산출:
0ms : start
2ms : hi 3
3ms : this runs in parallel! 8
3ms : hi 2
505ms : this runs in parallel! 7
505ms : hi 1
1007ms : this runs in parallel! 6
1508ms : this runs in parallel! 5
2009ms : this runs in parallel! 4
2509ms : hello 0
2509ms : this runs in parallel! 3
3010ms : this runs in parallel! 2
3509ms : hello 1
3510ms : this runs in parallel! 1
4511ms : hello 2
4511ms : heyy
이것을 보는 또 다른 방법은 한 기능에서 다른 기능으로 데이지 체인을 연결하는 것입니다. 다음과 같이 호출 된 모든 함수에 전역적인 함수 배열이 있습니다.
arrf: [ f_final
,f
,another_f
,f_again ],
그런 다음 실행하려는 특정 'f'에 정수 배열을 설정하십시오.
var runorder = [1,3,2,0];
그런 다음 'runorder'를 매개 변수로 사용하여 초기 함수를 호출합니다. 예 : f_start (runorder);
Then at the end of each function, just pop the index to the next 'f' to execute off the runorder array and execute it, still passing 'runorder' as a parameter but with the array reduced by one.
var nextf = runorder.shift();
arrf[nextf].call(runorder);
Obviously this terminates in a function, say at index 0, that does not chain onto another function. This is completely deterministic, avoiding 'timers'.
Put your code in a string, iterate, eval, setTimeout and recursion to continue with the remaining lines. No doubt I'll refine this or just throw it out if it doesn't hit the mark. My intention is to use it to simulate really, really basic user testing.
The recursion and setTimeout make it sequential.
Thoughts?
var line_pos = 0;
var string =`
console.log('123');
console.log('line pos is '+ line_pos);
SLEEP
console.log('waited');
console.log('line pos is '+ line_pos);
SLEEP
SLEEP
console.log('Did i finish?');
`;
var lines = string.split("\n");
var r = function(line_pos){
for (i = p; i < lines.length; i++) {
if(lines[i] == 'SLEEP'){
setTimeout(function(){r(line_pos+1)},1500);
return;
}
eval (lines[line_pos]);
}
console.log('COMPLETED READING LINES');
return;
}
console.log('STARTED READING LINES');
r.call(this,line_pos);
OUTPUT
STARTED READING LINES
123
124
1 p is 0
undefined
waited
p is 5
125
Did i finish?
COMPLETED READING LINES
참고URL : https://stackoverflow.com/questions/1859185/how-to-force-sequential-javascript-execution
'programing' 카테고리의 다른 글
Github Markdown 동일 페이지 링크 (0) | 2020.11.28 |
---|---|
npm 스크립트를 사용하여 js 파일을 어떻게 실행합니까? (0) | 2020.11.28 |
MongoDB는 SQL 주입 혼란을 어떻게 피합니까? (0) | 2020.11.28 |
원시 유형과 함께 getMethod ()를 사용하는 방법은 무엇입니까? (0) | 2020.11.28 |
bash 스크립트에서 $ {0 % / *}의 의미는 무엇입니까? (0) | 2020.11.28 |