Подтвердить что ты не робот

Как принудительно выполнить 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>

В этом вторая функция завершается перед первой функцией; что является самым простым способом (или есть один?), чтобы заставить вторую функцию отложить выполнение до тех пор, пока первая функция не будет завершена?

--- Edit ---

Итак, это был пример мусора, но благодаря Дэвиду Хедлунду я вижу в этом новом примере, что он действительно синхронный (вместе с сбоем моего браузера в процессе тестирования!):

<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, мне придется опубликовать отдельный вопрос об этом, если я не могу нигде себя достать!

4b9b3361

Ответ 1

Ну, setTimeout, согласно его определению, не будет удерживать поток. Это желательно, потому что, если бы это произошло, это заморозило бы весь пользовательский интерфейс за время ожидания. если вам действительно нужно использовать 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, не удерживать поток пользовательского интерфейса до его завершения. С AJAX, как и с setTimeout, вам придется работать с обратными вызовами.

Ответ 2

Я возвращаюсь к этим вопросам после всего этого времени, потому что мне потребовалось столько времени, чтобы найти то, что я считаю чистым решением: Единственный способ заставить javascript последовательное выполнение, которое я знаю, - использовать promises. Существуют исчерпывающие объяснения promises at: Promises/A и Promises/А +

Единственная библиотека, реализующая promises, которую я знаю, - это jquery, поэтому я хотел бы решить вопрос, используя jquery promises:

<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>

Выполняя обещание и связывая функции с .then(), вы гарантируете, что вторая функция будет выполнена только после того, как первая выполнит Это команда d.resolve() в longfunctionfirst(), которая дает сигнал для запуска следующей функции.

Технически shortfunctionsecond() не нужно создавать отложенные и возвращать обещание, но я влюбился в promises и стараюсь реализовать все с promises, извините.

Ответ 3

Я старую руку в программировании и недавно вернулся к своей старой страсти и изо всех сил стараюсь вписаться в этот объектно-ориентированный, управляемый событиями яркий новый мир, и, хотя я вижу преимущества несекретного поведения Javascript, есть время, когда это действительно мешает простоте и многоразовости. Простым примером, над которым я работал, было сделать снимок (мобильный телефон, запрограммированный в javascript, HTML, phonegap,...), изменить его размер и загрузить на веб-сайт. Идеальная последовательность:

  • Сделайте снимок
  • Загрузите фотографию в элемент img
  • Изменить размер изображения (с помощью Pixastic)
  • Загрузите его на веб-сайт
  • Информировать пользователя об ошибке успеха

Все это было бы очень простой последовательной программой, если бы каждый шаг возвращал управление следующему, когда он закончен, но на самом деле:

  • Сделать фотографию асинхронной, поэтому программа пытается загрузить ее в элемент img до ее существования
  • Загрузите фотографию асинхронно, чтобы изображение изменения размера начиналось до того, как img будет полностью загружен.
  • Изменение размера асинхронизируется, поэтому загрузка на веб-сайт начинается до того, как изображение будет полностью изменено.
  • Загрузка на веб-сайт - asyn, чтобы программа продолжалась до того, как фотография будет полностью загружена.

И btw 4 из 5 шагов включают функции обратного вызова.

Мое решение таким образом заключается в том, чтобы вложить каждый шаг в предыдущий и использовать .onload и другие подобные уловки, Он выглядит примерно так:

takeAPhoto(takeaphotocallback(photo) {
  photo.onload = function () {
    resizePhoto(photo, resizePhotoCallback(photo) {
      uploadPhoto(photo, uploadPhotoCallback(status) {
        informUserOnOutcome();
      });
    }); 
  };
  loadPhoto(photo);
});

(Надеюсь, я не допустил слишком много ошибок, привнося код в это, что реально, просто слишком отвлекает)

Это я считаю прекрасным примером, где async не является хорошим, а синхронизация - хорошая, потому что вопреки обработке событий Ui мы должны иметь каждый шаг до того, как будет выполнен следующий, но код - это кукла России, это путает и нечитабельно, повторное использование кода трудно достичь из-за всей вложенности, просто трудно довести до внутренней функции все необходимые параметры, не передавая их каждому контейнеру поочередно или используя злые глобальные переменные, и я бы любил, что результат всего этого кода даст мне код возврата, но первый контейнер будет закончен задолго до того, как код возврата будет доступен.

Теперь, чтобы вернуться к первому вопросу Тома, что было бы умным, легким для чтения и простым повторным использованием того, что было бы очень простой программой 15 лет назад, используя let say C и тупую электронную плату?

Требование на самом деле настолько просто, что у меня создалось впечатление, что я должен упустить фундаментальное понимание Javsascript и современного программирования. Разумеется, технология предназначена для повышения производительности труда?

Спасибо за ваше терпение

Раймонд динозавр; -)

Ответ 4

В javascript нет способа заставить код ждать. У меня была эта проблема, и так, как я это делал, это синхронный вызов SJAX на сервер, и сервер фактически выполняет спящий режим или выполняет некоторую активность перед возвратом и все время, js ждет.

Например, Sync AJAX: http://www.hunlock.com/blogs/Snippets:_Synchronous_AJAX

Ответ 5

В вашем примере первая функция действительно завершается до запуска второй функции. setTimeout не выполняет выполнение функции до тех пор, пока не будет достигнут тайм-аут, она просто запустит таймер в фоновом режиме и выполнит ваш оператор оповещения через указанное время.

В JavaScript нет собственного способа выполнить "сон". Вы можете написать цикл, который проверяет время, но это наложит много усилий на клиента. Вы также можете выполнить синхронный вызов AJAX, как описано emacsian, но это добавит дополнительную нагрузку на ваш сервер. Лучше всего это сделать, чтобы избежать этого, что должно быть достаточно простым для большинства случаев, как только вы поймете, как работает setTimeout.

Ответ 6

Я попробовал обратный вызов и не мог заставить это работать, что вы должны понимать, так это то, что значения все еще являются атомарными, хотя выполнение не выполняется. Например:

alert('1'); < --- эти две функции будут выполняться одновременно

alert('2'); < --- эти две функции будут выполняться одновременно

но это будет заставлять нас знать порядок выполнения:

loop=2;
total=0;
for(i=0;i<loop;i++) {
           total+=1;
           if(total == loop)
                      alert('2');
           else
                      alert('1');
}

Ответ 7

Если вы не настаиваете на использовании чистого Javascript, вы можете создать последовательный код в 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

Ответ 8

У меня была та же проблема, это мое решение:

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);
	}
}

Ответ 9

Другой способ взглянуть на это - связать цепочку от одной функции к другой. Имейте массив функций, который является глобальным для всех ваших вызываемых функций, например:

arrf: [ f_final
       ,f
       ,another_f
       ,f_again ],

Затем настройте массив целых чисел на конкретный 'f', который вы хотите запустить, например

var runorder = [1,3,2,0];

Затем вызовите начальную функцию с "runorder" в качестве параметра, например.   f_start (runorder);

Затем в конце каждой функции просто поместите индекс в следующий "f", чтобы выполнить отладчик и выполнить его, все еще передавая "runorder" в качестве параметра, но с уменьшенным массивом на один.

var nextf = runorder.shift();
arrf[nextf].call(runorder);

Очевидно, что это завершается функцией, например, с индексом 0, которая не привязана к другой функции. Это полностью детерминировано, избегая "таймеров".

Ответ 10

Поместите свой код в строку, iterate, eval, setTimeout и recursion, чтобы продолжить работу с оставшимися строками. Без сомнения, я уточню это или просто выкину, если оно не достигнет цели. Я намерен использовать его для имитации действительно, действительно базового пользовательского тестирования.

Рекурсия и setTimeout делают его последовательным.

Мысли?

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);

ВЫХОД

STARTED READING LINES
123
124
1 p is 0
undefined
waited
p is 5
125
Did i finish?
COMPLETED READING LINES