setTimeout в цикле с разным временем

У меня есть панель загрузки, которую я создаю, и я передаю разные миллисекунды и параметры стиля в var barMovement.

Моя проблема в том, что в функции setTimeout последние параметры, которые имеют время 100 миллисекунд, не выводятся последними.

Когда я консоль веду журнал, результаты получаются как 100, 200, 200, 100, 200, 300, тогда как должно быть 100, 200, 200, 200, 300, 100 .

Если я правильно понимаю, последний параметр 100 выводится первым, потому что он быстрее, но есть ли исправление для этого или способ сделать задержку setTimeout до завершения предыдущего цикла setTimeout?

Спасибо!

function BarSequence(style){
 this.style = style

 this.move = function(styles) {
  var i = 0;

  for(len = styles.length; i < len; i++){

    (function loopy(index) {

        setTimeout(function() {
          console.log(style[index])
        }, i * style[index][0]);
    })(i);

   }
  }
}

var barMovement = new BarSequence([
[100, { width: '10%' }],
[200, { width: '20%' }],
[200, { width: '50%' }],
[200, { width: '80%' }],
[300, { width: '90%' }],
[100, { width: '100%' }]
]);

barMovement.move(barMovement.style);

person SamAdamsBoston    schedule 23.02.2017    source источник
comment
Почему вы умножаете время на i в i * style[index][0]?   -  person ibrahim mahrir    schedule 23.02.2017
comment
Вы умножаете его на индекс. Итак, ваши таймауты равны 0, 200, 400, 600, 1200, 500, поэтому последний будет раньше между 400 и 600.   -  person epascarello    schedule 23.02.2017
comment
Возможный дубликат понимания порядка SetTimeout   -  person SamAdamsBoston    schedule 24.02.2017


Ответы (2)


Вы умножаете его на индекс. Итак, ваши таймауты равны 0, 200, 400, 600, 1200, 500, поэтому последний будет раньше между 400 и 600.

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

var barMovement = [
  [100, {width: '10%'}],
  [200, {width: '20%'}],
  [200, {width: '50%'}],
  [200, {width: '80%'}],
  [300, {width: '90%'}],
  [100, {width: '100%'}]
];

var cnt = 0;

function run() {
  window.setTimeout(function() {
    document.getElementById("bar").style.width = barMovement[cnt][1].width
    cnt++;
    if (cnt < barMovement.length) run();
  }, barMovement[cnt][0])
}

run()
#bar {
  background-color: green;
  width: 0;
}
<div id="bar">&nbsp;</div>

person epascarello    schedule 23.02.2017

Я считаю, что единственный способ сделать это - объявить setTimeouts друг в друге, что-то вроде:

setTimeout(function(){
    //execute the work to be done
    setTimeout(function(){
        //execute the work to be done
        // ... and so on
    })
});

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

РЕДАКТИРОВАТЬ: этот ответ довольно хорошо объясняет, как обрабатывается выполнение setTimeouts.

РЕДАКТИРОВАТЬ 2: это плохой подход, поскольку удаление динамизма кода не является хорошей практикой. Проверьте ответ от @epascarello.

person Bruno Santos    schedule 23.02.2017
comment
@epascarello, вы совершенно правы, статический код никогда не должен быть подходом, ответ тут же - person Bruno Santos; 23.02.2017