Typescript - 来自for循环中动态变量的setTimeout自定义时间

Typescript - setTimeout custom time from variable that is dynamic in for loop

所以我有这个函数,它的超时每 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) 更改为我从 促销 获得的自定义变量。这是促销活动:

所以每张图片或 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));

}

这在理论上应该可行,但计时器走得太远了。 第一张照片应该持续4s,但持续3s。第二张图片应该持续 3 秒,但持续 6 秒。第三张图应该是10秒却持续了4秒...

我不明白我做错了什么。为什么即使我发送了正确的变量 promoDisplayTime.

计时器也会关闭

具有虚拟数据的 StackBlitz:https://stackblitz.com/edit/angular-r6ejw9?file=src%2Fapp%2Fapp.component.html

在 Angular 上下文中工作时,我建议拥抱 RxJs 的强大功能。

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。

现场演示:https://stackblitz.com/edit/angular-6c4pqt?file=src/app/app.component.ts

我看到两个错误:

  1. 您从 0 开始计数 i。结果是当您计算超时值时第一个值(6 秒)变为 0,因此几乎立即执行第一个函数。然后第二个值(3 秒)用于显示第二张图片,并乘以 i,此时为 1(因此您看到第一个持续 3 秒)。第三张图同理

  2. 您使用 i 作为某种分隔符同时调用所有 setTimeout。要实现您的需要,您应该在 setTimeout for picture n 结束后调用 setTimeout for picture n + 1

根据这个答案Is setTimeout a good solution to do async functions with javascript?

setTimeout(function(){...}, 0) simply queues the code to run once the current call stack is finished executing.

所以发生的事情是 for 循环以 promotions[i].time = 4 结束,并且 setTimeout 代码段以该值运行(至少这是我在 StackBlitz 中的代码中看到的)...

这是使用异步函数和 setTimeout() 的可能解决方案之一。

使用异步功能,我们确保下一张幻灯片不会在第一张幻灯片之前执行。

你应该注意 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