Adraxas Nazaron
Adraxas Nazaron

Reputation: 60

Repeating a function indefinitely, preferably without using setInterval()

I am building a slide show framework and was having trouble figuring out the best way to cycle the animation function, I know I could use setInterval() but was wondering if there was a better way to repeat it without being to resource intensive.

JAVASCRIPT:

class slideShow {
    constructor(imgDir, dataList) {
        this.imgDir = imgDir;
        this.dataList = dataList;
        this.settings = 0;
        this.imgList = 0;
        this._init();
    }
    _init(){
        $.getJSON(`${this.imgDir}/${this.dataList}.json`, (data)=>{
            this.settings = data.settings;
            this.imgList = data.imgList;
        })
    }
    start(){
        for(let img of this.imgList){
            $(this.settings.selector).fadeOut(this.settings.fadeTime, ()=>{
                $(this.settings.selector).attr("src",`${this.imgDir}/${img}`);
                $(this.settings.selector).fadeIn(this.settings.fadeTime);
            });
        }
    }
}

JSON:

{
    "settings":{
        "selector":"#slideShow",
        "fadeTime":1000
    },
    "imgList":[
        "slide_01.jpg",
        "slide_02.jpg",
        "slide_03.jpg"
    ]
}

Upvotes: 1

Views: 377

Answers (2)

Alnitak
Alnitak

Reputation: 339786

A simple solution is to pseudo-recursively loop from the "completion callback" of the final step of the animation.

start() {
    var current = 0;
    (function loop() {
        let img = imgList[current++];
        current %= imgList.length;
        let $sel = $(this.settings.selector);
        $sel.fadeOut(this.settings.fadeTime, () => {
            $sel.attr("src",`${this.imgDir}/${img}`);
            $sel.fadeIn(this.settings.fadeTime, loop); // <-- here
        });
    })();
}

Note that I've removed the for ... of loop - each pass of the loop function here just handles one frame of the slideshow.

This would resolve what appears to be a bug in your original code, where you'd get three consecutive fadeOut animations (two of which would of course be invisible) because nothing in your code allows for the first cycle of fadeOut, change image, fadeIn to complete before the next iteration of the for ... of loop starts.

Upvotes: 2

guest271314
guest271314

Reputation: 1

You can use .then(), jQuery .promise(), recursion

class slideShow {
    constructor(imgDir, dataList) {
        this.imgDir = imgDir;
        this.dataList = dataList;
        this.settings = 0;
        this.imgList = 0;
        this._init();
    }
    _init(){
        $.getJSON(`${this.imgDir}/${this.dataList}.json`, (data)=>{
            this.settings = data.settings;
            this.imgList = data.imgList;
        }).then(this.start)
    }
    start(){
        for(let img of this.imgList){
            $(this.settings.selector).fadeOut(this.settings.fadeTime, ()=>{
                $(this.settings.selector).attr("src",`${this.imgDir}/${img}`);
                $(this.settings.selector).fadeIn(this.settings.fadeTime);
            });
        }
        $(this.settings.selector).promise()
        .then(() => this.start() /* or this._init() */)
    }
}

Upvotes: 1

Related Questions