简体   繁体   中英

Enable Jquery Only after Javascript recursive function is done executing

//image sequence functions
//preload array
/**
 * Preload images in a directory.
 * @param {string} baseurl 
 * @param {string} extension
 * @return {Promise} resolve an Array<Image>.
 */
function preloadImages(baseurl, extension, starter) {
    return new Promise(function (res) {
        var i = starter;
        var images = [];
        // Inner promise handler
        var handler = function (resolve, reject) {
            var img = new Image;
            var source = baseurl + i + '.' + extension;
            img.onload = function () {
                i++;
                resolve(img);
            }
            img.onerror = function () {
                reject('Rejected after ' + i + 'frames.');
            }
            img.src = source;
        }
        // Once you catch the inner promise you resolve the outer one.
        var _catch = function () {
            res(images)
        }
        var operate = function (value) {
            if (value) images.push(value);
            // Inner recursive promises chain.
            // Stop with the catch resolving the outer promise.
            new Promise(handler).then(operate).catch(_catch);
        }
        operate();
    })
}

/**
 * Draw an Array of images on a canvas.
 * @param {Canvas} canvas 
 * @param {Array<Image>} imagelist 
 * @param {number} refreshRate 
 */
function play(canvas, imagelist, refreshRate, frameWidth, frameHeight, percentage) {
    // Since we're using promises, let's promisify the animation too.
    return new Promise(function (resolve) {
        // May need to adjust the framerate
        // requestAnimationFrame is about 60/120 fps depending on the browser
        // and the refresh rate of the display devices.
        var ctx = canvas.getContext('2d');
        var ts, i = 0,
            delay = 1000 / refreshRate;
        var roll = function (timestamp) {
            if (!ts || timestamp - ts >= delay) {
                // Since the image was prefetched you need to specify the rect.
                ctx.drawImage(imagelist[i], 0, 0, frameWidth, frameHeight);
                i++;
                ts = timestamp;
            }
            if (i < imagelist.length * percentage)
                requestAnimationFrame(roll);
            else
                resolve(i);
        }
        roll();
    })
}
//combine preload and play into one
function preloadAndPlay(ID, actor, event, percentage) {
    var preload = preloadImages('/static/videos/' + actor + '/Clip_' + event + '/', 'png', 1);
    preload.then(function (value) {
        //console.log('starting play');
        //canvas html5 object with ID
        var canvas = document.getElementById(ID);
        play(canvas, value, 30, 960, 540, percentage) // ~30fps
            .then(function (frame) {
                console.log('roll finished after ' + frame + ' frames.')
            })
    });
}   



$.when(preloadAndPlay('myImage', actor, event, percentage)).done(function(){
        $('.data').click(function () {
            if ($(this).is(':checked')) {
                $(this).removeClass('hidden');
                $(that).addClass('hidden');
            }
            that = this;
        });
        $('.data').change(function () {
            if (('input[name=b]:checked').length) {
                $('#trial_next').prop('disabled', false);
                cbChecked = document.querySelector('[name="b"]:checked').value;
                debug(cbChecked);
            }
        });
    });

I would like the .change and .click jquery to be only enabled after preloadAndPlay javascript function is COMPLETELY done executing. Jquery is are suppose to be allow radio buttons that can be selected. preloadAndPlay is a function that loads a series of images then displays them with html5 canvas so it seems like a video/animation. See above for the preloadAndPlay function that uses promise and recursion. The code works it's just I don't want people to make selection before the video ends. Above is the code I tried.

There are several issue at code at Question. At preloadImages function the parameter at function passed to Promise constructor is named res , though resolve() is called within function at <img> load event, though resolve is undefined within the function. handler is not called, not reaching call to undefined resolve() . operate function within Promise constructor is not necessary. No value is return ed from operate , see Why is value undefined at .then() chained to Promise? .

You can use Promise.all() to pass an iterable object where chained .then() should be called when all of the values or Promise values passed are fulfilled.

Not certain what the expected effect of play() call is, nor is that portion of code mentioned as being a part of the original inquiry. Adjusted code at staccksnippets to call requestAnimationFrame for each image.

 const baseurl = "https://lorempixel.com/50/50/"; const data = ["cats", "nature", "city"]; const canvas = document.querySelector("canvas"); function preloadImages(image) { return new Promise(function(resolve) { var img = new Image; var source = baseurl + image; img.onload = function() { resolve(img); } img.onerror = function() { reject('Rejected after ' + i + 'frames.'); } img.src = source; }) } function play(canvas, imagelist, refreshRate, frameWidth, frameHeight, percentage) { // Since we're using promises, let's promisify the animation too. return new Promise(function(resolve) { // May need to adjust the framerate // requestAnimationFrame is about 60/120 fps depending on the browser // and the refresh rate of the display devices. var ctx = canvas.getContext('2d'); var ts, i = 0, delay = 1000 / refreshRate; var roll = function(timestamp) { if (!ts || timestamp - ts >= delay) { // Since the image was prefetched you need to specify the rect. ctx.drawImage(imagelist[i], 0, 0, frameWidth, frameHeight); i++; ts = timestamp; } if (i < imagelist.length /* * percentage */ ) requestAnimationFrame(roll); else resolve(i); } roll(); }) } function preloadAndPlay(percentage) { var preload = Promise.all(data.map(preloadImages)) .then(function(images) { console.log("preloadImages complete, images:", images); images.forEach(function(img) { document.body.appendChild(img) }); return images }) .catch(function(err) { console.error(err); throw err; }); return preload.then(function(value) { console.log("preload complete, value:", value); return play(canvas, value, 30, 960, 540, percentage) // ~30fps .then(function(frame) { console.log('roll finished after ' + frame + ' frames.'); return "done"; }) }); } preloadAndPlay() .then(function(data) { console.log(data); }) .catch(function(err) { console.error(err) }) 
 <canvas></canvas> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM