Typescript - пользовательское время setTimeout из переменной, которая является динамической c в цикле for - PullRequest
0 голосов
/ 27 января 2020

Итак, у меня есть эта функция, у которой время ожидания меняется каждые 3 с:

 setActiveImage(promotions) {
    for (let i = 0; i <= promotions.length - 1; i++) {
      setTimeout(()=> {
        this.activeImage = 'http://myrul/public/Commercials/' + promotions[i].commercial_file[0].file;
      }, 3000*(i)); //CHANGE PICTURE EVERY 3s

    }
  }

Теперь я хочу изменить время (3000) на пользовательскую переменную, которую я получаю из promotions, Это рекламные акции:

enter image description here

Так что у каждой фотографии или экземпляра i есть свое время.

Вот что я сделал :

for (let i = 0; i <= promotions.length - 1; i++) {

  var x = promotions[i].time; //GET TIME
  var y = +x; //TURN STRING TO NUMBER
  var z = y * 1000; //TURN SECOND INTO MILISECONDS

  var promoDisplayTime = z; //CUSTOM TIME

  setTimeout(()=> {
    this.activeImage = 'http://myurl/Commercials/' + promotions[i].commercial_file[0].file;
  }, promoDisplayTime*(i));

}

Теоретически это должно работать, но таймер отключается. Первая картинка должна длиться 4 секунды, но длится 3 секунды. Второе изображение должно длиться 3 с, но длится 6 с. Третья картинка должна быть 10 с, но длится 4 с ...

Я не понимаю, что я делаю неправильно. Почему таймер выключен, хотя я отправляю правильную переменную promoDisplayTime .


StackBlitz с фиктивными данными: https://stackblitz.com/edit/angular-r6ejw9?file=src%2Fapp%2Fapp.component.html

Ответы [ 4 ]

1 голос
/ 30 января 2020

Вот одно из возможных решений с помощью функции asyn c и setTimeout ().

С помощью функции asyn c мы гарантируем, что следующий слайд не будет выполнен до того, как первый слайд будет ,

В setTimeout следует следить за тем, чтобы таймер выполнял заданную функцию ПОСЛЕ истечения времени.

Итак, рабочий пример должен выглядеть примерно так:

activeImage: string = 'https://pngimage.net/wp-content/uploads/2018/06/start-png-.png';

  promotions = [
    {
      time: 6,
      pic: 'https://pngimage.net/wp-content/uploads/2018/06/1-an-png-1.png'
    },
    {
      time: 3,
      pic: 'https://upload.wikimedia.org/wikipedia/commons/1/10/MRT_Singapore_Destination_2.png'
    },
    {
      time: 4,
      pic: 'https://upload.wikimedia.org/wikipedia/commons/a/aa/L%C3%ADnea_3_CAMETRO.png'
    }
  ];

  ngOnInit() {
      this.setActiveImage();
  }

  setActiveImage() {
    let _this = this;
    countDown();

    function printer(i) {

      return new Promise(resolve => {
        _this.activeImage = _this.promotions[i].pic;
        setTimeout(function () {
          resolve(true);
        }, _this.promotions[i].time * 1000);
      });
    }

    async function countDown() {
      for (var i = _this.promotions.length -1; i >= 0; i--) {
        await printer(i);
      }
    }

  }

Демонстрация в реальном времени: https://stackblitz.com/edit/angular-qwtgm2

0 голосов
/ 27 января 2020

Я вижу две ошибки:

  1. Вы считаете i от 0. В результате первое значение (6 секунд) становится 0, когда вы вычисляете значение времени ожидания, поэтому первая функция выполняется почти сразу. Затем второе значение (3 секунды) используется для показа второго изображения и умножается на i, равное 1 в этой точке (таким образом, вы видите первое, продолжающееся 3 секунды). Третье изображение следует той же логике c.

  2. Вы вызываете все setTimeout с одновременно, используя i как своего рода разделитель. Чтобы достичь того, что вам нужно, вы должны позвонить setTimeout для изображения n + 1 после окончания setTimeout для изображения n.

0 голосов
/ 27 января 2020

за этот ответ Является ли setTimeout хорошим решением для выполнения асинхронных c функций с javascript?

setTimeout(function(){...}, 0) просто ставит код в очередь для запуска после текущего стек вызовов завершен.

, так что происходит, поскольку для l oop заканчивается promotions[i].time = 4, и фрагмент кода setTimeout выполняется с этим значением (по крайней мере, это то, что я вижу в вашем коде в StackBlitz) ...

0 голосов
/ 27 января 2020

При работе в контексте Angular я бы рекомендовал использовать Rx Js.

const MOCKED_DATA = [
  {
    time: "6",
    pic: "https://pngimage.net/wp-content/uploads/2018/06/1-an-png-1.png"
  },
  {
    time: "3",
    pic:
      "https://upload.wikimedia.org/wikipedia/commons/1/10/MRT_Singapore_Destination_2.png"
  },
  {
    time: "4",
    pic:
      "https://upload.wikimedia.org/wikipedia/commons/a/aa/L%C3%ADnea_3_CAMETRO.png"
  }
];

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  promotions$ = from(MOCKED_DATA).pipe(
    map(promotion => of(promotion.pic).pipe(delay(1000 * +promotion.time))),
    mergeAll(),
    startWith("https://pngimage.net/wp-content/uploads/2018/06/start-png-.png")
  );
}

, а затем в вашем шаблоне:

<img [src]="promotions$ | async" alt="Responsive image of item">

Демонстрационная версия: https://stackblitz.com/edit/angular-xjcrgd?file=src / app / app.component.ts

Редактировать: я не уверен, является ли время относительным или нет в вашем вопросе, но после прочтения снова, я думаю, что это так. Если это так, то вы можете создать функцию переотображения, которая будет иметь абсолютное время, подобное этому:

const remapToAbsoluteTime = (data: ServerContent[]): LocalContent[] =>
  data.reduce((acc, x) => {
    if (!acc.length) {
      acc.push({
        ...x,
        time: +x.time
      });
    } else {
      acc.push({
        ...x,
        time: acc[acc.length - 1].time + +x.time
      });
    }

    return acc;
  }, []);

Тогда вам будут упорядочены фотографии 1, 2, 3.

Live демо: https://stackblitz.com/edit/angular-6c4pqt?file=src / app / app.component.ts

...