2011-01-08 5 views
5

Да, я знаю - этот вопрос имеет тысячи ответов. пожалуйста, не говорите мне о setTimeout метод потому что - да, все возможно с этим, но не так просто, как с использованием метода sleep().JavaScript sleep

Например:

function fibonacci(n) { 
    console.log("Computing Fibonacci for " + n + "..."); 
    var result = 0; 

    //wait 1 second before computing for lower n 
    sleep(1000); 
    result = (n <= 1) ? 1 : (fibonacci(n - 1) + fibonacci(n - 2)); 

    //wait 1 second before announcing the result 
    sleep(1000); 
    console.log("F(" + n + ") = " + result); 

    return result; 
} 

, если вы знаете, как получить тот же результат с помощью setTimeout - скажите мне;) fibanacci довольно простая задача, потому что есть не более 2 рекурсии, но как насчет п -рекурсии (например, fib (1) + fib (2) + .. + fib (n)) и спать после каждого «+»? Нет, спать было бы муууууучем проще.

Но все же я не могу получить рабочий пример его реализации. while (curr - start < time) { curr = (...) } сложно, но это не сработает (просто останавливает мой браузер, а затем бросает все консольные журналы сразу).

+3

Рассматривали ли вы использование лучшего алгоритма? – Yacoby

+5

В чем вопрос? –

+1

@Yacoby - Для вычисления Фибоначчи? Это просто пример, я знаю, что это медленно, как черт. @ Oli - как переписать его в setTimeout или как реализовать рабочий сон() – Diazath

ответ

19

Я не в полной мере понять, что вы просите, но я собираюсь ответить на эту часть:

, если вы знаете, как получить тот же результат с помощью SetTimeout - скажите мне

Основное отличие заключается в том, что sleep (как используется на многих других языках) является синхронным, а setTimeout (и многие другие JavaScript-концепции, например AJAX), являются асинхронными. Итак, чтобы переписать вашу функцию, мы должны учитывать это. В основном, мы должны использовать функцию обратного вызова для извлечения «возвращаемое значение», а не фактического возврата-заявления, поэтому он будет использоваться, как это:

fibonacci(7, function(result) { 
    // use the result here.. 
}); 

Так как для реализации:

function fibonacci(n, callback) { 
    console.log("Computing Fibonacci for " + n + "..."); 
    var result = 0; 

    var announceAndReturn = function() { 
    setTimeout(function() { 
     // wait 1 second before announcing the result 
     console.log("F(" + n + ") = " + result); 
     callback(result); // "returns" the value 
    }, 1000); 
    }; 

    // wait 1 second before computing lower n 
    setTimeout(function() { 
    if (n <= 1) { 
     result = 1; 
     announceAndReturn(); 
    } 
    else { 
     var resultsLeft = 2; 

     var handler = function(returned) { 
     result += returned; 
     resultsLeft--; 
     if (resultLeft == 0) 
      announceAndReturn(); 
     } 

     fibonacci(n-1, handler); 
     fibonacci(n-2, handler); 
    } 
    }, 1000); 
} 

Я также хотел бы отметить, что no, это не проще, чем использовать sleep. Зачем? Поскольку этот код является асинхронным, и это просто сложнее, чем синхронный код для большинства пользователей. Для того, чтобы начать думать таким образом, требуется практика.

Вверху? Это позволяет вам писать неблокирующие алгоритмы, превосходящие их синхронные копии. Если вы еще не слышали об Node.js, вы можете проверить это, чтобы лучше понять преимущества этого. (Многие другие языки имеют библиотеки для работы с асинхронным IO, а также, но до тех пор, как говорили о JavaScript ..)

+1

Так как я вижу, у меня нет другого выбора, кроме как начать об этом. Благодарю. – Diazath

+1

@ Диасат: Да, это в значительной степени. Вы не пожалеете об этом, но это освобождает ваш разум;) – Jakob

+0

солидный ответ Якоб, он забирает меня дольше, чем я хотел бы получить асинхронное программирование (обратные вызовы, контекст/закрытие), но я получаю там после многих лет c/C++. –

2

a better algorithm Просто используйте без петель или рекурсии, и избежать необходимости setTimeout()/sleep(). Пример

function fibonacci(n) { 
    return Math.round(Math.pow((Math.sqrt(5) + 1)/2, Math.abs(n))/Math.sqrt(5)) * (n < 0 && n % 2 ? -1 : 1); 
} 

Использование:

// Log the first 10 Fibonacci numbers (F0 to F9) to the console 
for (var i = 0; i < 10; i++) { 
    console.log(fibonacci(i)); 
} 
+1

Он не просит лучшего алгоритма для вычисления фактической последовательности. По какой-то причине он хочет спать (может быть, доказать, что его алгоритм ОЧЕНЬ медленный для не-крошечного N). Однако я не буду снижать, так как вопрос так плохо выражен. – Jakob

+0

@ Якоб: Я понимаю это. Я фактически опубликовал другой ответ раньше, объяснив, что реализация 'sleep()' является плохой идеей, но это можно сделать и зарыть в downvotes *, потому что * это плохая идея. Ну, теперь он снят. –

+1

Ха-ха, я вижу. Жемчуг для свиней Я полагаю :) (не обижайте людей, которые не привыкли к асинхронному коду, но вы чего-то не хватает) – Jakob

3

Проблема с функцией в sleep() типа в браузере (или любой другой графический интерфейс среды для этого вещества) является то, что она является средой, управляемой событиями, и Wouldn» t быть в состоянии sleep() в том, как вы его описываете.

Метод setTimeout() работает, потому что он создает событие и устанавливает триггер для этого события как момент времени.Поэтому система может контролировать управление ожиданием обработчика событий, а сам Javascript может продолжать выполнять другие действия.

В веб-браузере практически все работает таким образом. Функция мыши/зависание/etc - это триггеры событий. Запросы Ajax не сидят и ждут ответа с сервера; они устанавливают событие для запуска при получении ответа.

Действия, основанные на времени, также выполняются с помощью триггеров событий, используя такие функции, как setTimeout().

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

Функция Javascript sleep() (особенно то, как она была реализована в другом ответе здесь!) В основном приведет к выгоранию ваших циклов процессора, пока он ждет часы. sleep() останется активным процессом, что означает, что другие события могут не обрабатываться сразу - это означает, что ваш браузер перестанет отвечать на щелчки мыши и т. Д. На время сна. Нехорошо.

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

Надеюсь, что это поможет немного объяснить вам кое-что.

+2

Все, что вы говорите, справедливо для Javascript * в асинхронной среде. * В языке программирования нет ничего, кроме JavaScript. настаивает на асинхронном режиме исполнения. Фактически большинство серверных сред Javascript синхронны; Rhino - хороший пример. – Pointy

+0

@Pointy - спасибо; Я изменил ответ, чтобы подчеркнуть тот факт, что мы говорим конкретно о среде браузера. – Spudley

+1

@Pointy И тогда есть «oh so awesome» Node.js, который полностью асинхронен (да, есть несколько специальных методов синхронизации для чтения файлов, но они предназначены для конфигурации). Но да, вообще нет ничего особенного в JS, на самом деле, Node реализует setTimeout и т. Д. :) –

0

Почему вы хотите «спать» при вычислении чего-либо? Сон в любое время почти всегда плохая идея на любом языке. По сути, он говорит, что нить перестает делать что-либо за этот период времени.

Итак, на языке, подобном javascript, который имеет только один поток (забыв «веб-работников»), какую выгоду вы могли бы извлечь для приостановки ВСЕГО вычислений? Это плохая идея, забудьте об этом.

Теперь к проблеме, которую вы написали, хотя я не думаю, что это ваша фактическая проблема. Почему вы хотите сделать паузу на секунду при вычислении этой последовательности? Даже для вычисления первых 6 чисел в последовательности, это займет около 8 секунд. Зачем? Какая возможная причина заключается в том, чтобы сделать паузу в течение секунды между рекурсивными вызовами? Прекрати это. Убери это.

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

function fib(n) { 
    ... 
    result = fib(); 
    ... 
    setTimeout(function() { 
     console.log("Fib for " + n + " is " + result); 
    },1000); 
} 

Не пытайтесь реализовать «сон». Не делайте паузы во время вычисления.

+2

Возможно, он настраивает алгоритм для какой-то педагогической цели, поэтому между шагами вычисления требуется «sleep()». Другими словами, возможно, сон сделан для некоторой иллюстративной анимации на веб-странице. – Pointy

+0

@Pointy - это именно то, что я делаю. – Diazath

+1

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

25

Вопрос в том, как реализовать sleep() в JavaScript, не так ли?

function sleep(ms) { 
    var start = new Date().getTime(), expire = start + ms; 
    while (new Date().getTime() < expire) { } 
    return; 
} 

Я просто проверял, как так:

console.log('hello'); 
sleep(5000); 
console.log('world'); 

работает для меня.

(В качестве мета-комментария: Я приземлился здесь, потому что у меня есть особая потребность в этой функции.Такие потребности возникают, когда вы нуждаетесь в для блокировки, ожидая значения. Даже в JavaScript.)

+1

Нет. Предположительно, Q - это синхронное и асинхронное программирование и как его асинхронно кодировать. Я бы не понял, что я сам основывался на Q. Но это становится очевидным из комментариев автора по [принятому ответу] (http://stackoverflow.com/a/4634095/923794). Может быть спорным начать отвечать на вопросы с уже принятыми ответами. Но, конечно, это дело в каждом случае, и может быть полезно. Аскеры могут позже изменить принятые ответы. – cfi

+1

Кодирование синхронного 'sleep()', которое просто сжигает циклы процессора, редко имеет смысл. В большинстве операционных систем, даже если вы делаете это так, вы не можете предотвратить, что контроль будет заимствован из вашего процесса. Фактически, именно по этой причине активное циклирование и опрос времени менее точны, чем освобождение системы управления и попросить ее разбудить вас в определенное время (= событие). Возможно, в ОС реального времени или на привилегированном уровне без привилегий есть прецедент. – cfi

+2

С другой стороны, синхронный 'sleep()' может быть очень полезен, например. для проверки некоторого эзотерического 'setInterval()/clearInterval()' поведения в присутствии возможной (но еще не существующей) очень долговременной задачи JS. Это единственный ответ, который отвечает на вопрос «Как спать() в JS».Не то, чтобы я думаю, что это ответ, который большинство людей хочет, но это потому, что большинство людей, требующих 'sleep()', на самом деле не хотят 'sleep()'. – user508633