2016-09-29 4 views
1

Я играл с обещаниями и пытался создать какое-то уведомление о ходе.jQuery отложенное обещание о ходе выполнения

Код выполняет все функции в правильном порядке, но обновления прогресса выполняются непосредственно перед разрешением, а не когда они на самом деле происходят.

Может ли кто-нибудь указать, что я делаю неправильно?

function start(x) { 
    console.log("Start: " + x); 
    var promise = process(x); 
    console.log("promise returned"); 
    promise.then(function(data) { 
     console.log("Completed: " + data); 
    }, function(data) { 
     console.log("Cancelled: " + data); 
    }, function(data) { 
     console.log("In Progress: " + data); 
    }); 
    } 

    function process(x) { 
    var deferred = $.Deferred(); 
    var promise = deferred.promise(); 

    // process asynchronously 
    setTimeout(function() { 
     for (var i=0 ; i<x ; i++) { 
     sleep(1000); 
     deferred.notify(i); 
     } 

     if (x % 2 === 0) { 
     deferred.reject(x); 
     } else { 
     deferred.resolve(x); 
     } 
    }, 0); 

    return promise; 
    } 

    function sleep(sleepDuration) { 
    var now = new Date().getTime(); 
    while(new Date().getTime() < now + sleepDuration){ /* do nothing */ } 
    } 

    start(3); 

Fiddle здесь: https://jsfiddle.net/n86mr9tL/

ответ

1

Задержка таймера осуществляется с while(), будет "блок" - т.е. боров процессор.

Блокировка не только предотвращает запуск другого javascript, но также препятствует надежному обновлению экрана браузера, включая консоль. Таким образом, если операторы deferred.notify(i) и console.log("In Progress: " + data) стреляют, консоль не обновляется до тех пор, пока процессор не станет свободным.

Неудивительно, что решение заключается не в использовании while().

К счастью, JavaScript imcludes два встроенных методов window.setTimeout() и window.setInterval(), которые концептуально отличаются от while() бездельника, но выполняют ту же роль .... без блокировки.

  • window.setInterval(fn, t) пожары действуют fn каждые т миллисекунд,
  • window.setTimeout(fn, t) пожары действуют fn один раз, после т миллисекунд.

Оба метода возвращают непрозрачную ссылку, которая позволяет их отменять.

В приведенном ниже коде start() немодифицирован, process() сильно изменен и sleep() исчез.

process() теперь делает следующее:

  • создает JQuery Отложенным и возвращает обещание, полученное из него,
  • establises setInterval() от 1000 миллисекунд (1 секунду), функция которого:
    • подсчитывает, сколько раз он был вызван,
    • звонки deferred.notify() каждую секунду до прилавка i достигает Указанная максимальная x,
  • , когда указанный максимум достигается:
    • интервал, который в противном случае молча пролетать бесконечности, очищается,
    • deferred.resolve() или deferred.reject() призваны урегулировать Отложенный (и его обещание),
function start(x) { 
    console.log("Start: " + x); 
    process(x).then(function(data) { 
     console.log("Completed: " + data); 
    }, function(data) { 
     console.log("Cancelled: " + data); 
    }, function(data) { 
     console.log("In Progress: " + data); 
    }); 
} 

function process(x) { 
    return $.Deferred(function(dfd) { 
     var i = 1; 
     var intervalRef = setInterval(function() { 
      if(i < x) { 
       dfd.notify(i++); 
      } else { 
       clearInterval(intervalRef); 
       dfd[(x % 2 === 0)?'reject':'resolve'](x); 
      } 
     }, 1000); 
    }).promise(); 
} 

console.clear(); 
start(3); 

Updated fiddle

+0

Nice один. Теперь все ясно. –

Смежные вопросы