Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When Javascript callbacks can't be used

I know that you're not supposed to do blocking in Javascript and I've never been unable to refactor away from having to do that. But I've come across something that I don't know how to handle with callbacks. I'm trying to use Downloadify with html2canvas (this is for IE only, downloading data URIs doesn't work in IE). You have to specify a data function so the Flash object knows what to download. Unfortunately, html2canvas is asynchronous. I need to be able to wait until the onrendered event is filled in before I can get the data URI.

$('#snapshot').downloadify({
        filename: function(){
            return 'timeline.png';
        },
        data: function(){
            var d = null;
            html2canvas($('#timeline'),{
                onrendered:function(canvas){
                    d = canvas.toDataURL();
                }
            });

            //need to be able to block until d isn't null

            return d;
        },
        swf: '../static/bin/downloadify.swf',
        downloadImage: '../static/img/camera_icon_32.png?rev=1',
        width: 32,
        height: 32,
        transparent: true,
        append: false
});

I'm open to suggestions on other ways to do this, but I'm stuck.

EDIT - A couple of comments have made it seem that more information on Downloadify is needed (https://github.com/dcneiner/Downloadify). Downloadify is a Flash object that can be used to trigger a browser's Save As window. The downloadify() function is simply putting initializing the Flash object and sticking an <object/> tag in the element. Since it's a Flash object, you can't trigger events from Javascript without causing a security violation.

I'm using it for IE only to download an image of a Canvas element. In all other browsers, I can just use a data URI, but IE is a special flower.

like image 567
monitorjbl Avatar asked Feb 15 '13 01:02

monitorjbl


People also ask

Under what circumstances are callbacks useful?

Callbacks are generally used when the function needs to perform events before the callback is executed, or when the function does not (or cannot) have meaningful return values to act on, as is the case for Asynchronous JavaScript (based on timers) or XMLHttpRequest requests.

When promise can be used instead of callback?

Promises are JavaScript objects that represent an eventual completion or failure of an asynchronous operation. A promise is a returned object where you attach callbacks, instead of passing callbacks into a function. the place where you attach the callback after a successful completion of a task is called, .

Are callbacks still used in JavaScript?

Yes. The print( ) function takes another function as a parameter and calls it inside. This is valid in JavaScript and we call it a “callback”. So a function that is passed to another function as a parameter is a callback function.

Are callbacks faster than promises?

So from my findings i assure you ES6 promises are faster and recommended than old callbacks.


1 Answers

For the poor soul that spends an entire night trying to get an HTML5 feature to work on IE9, here's what I ended up using. I can sorta-kinda get away with it because we aren't too terribly concerned about IE users getting a less user friendly experience and this is an internal application. But, YMMV.

Basically, Downloadify will do nothing when the return string is blank. So, due to the asynchronous nature of html2canvas's rendering, the first time a user clicks, nothing will happen. The second time (assuming the render is done, if not nothing will continue to happen until it is), the value is not blank and the save proceeds. I use the onCancel and onCoplete callbacks to blank out the value again to ensure that the next time the user tries to save, the image is not too stale.

This doesn't account for the event that the user changes the DOM in some way in between clicks, but I don't know what can be done for that. I'm not at all proud of this, but IE is what it is. It works, which is enough for now.

    var renderedPng = '';
    var rendering = false;

    $('#snapshot').downloadify({
        filename: function(){
            return 'timeline.png';
        },
        data: function(){
            if(!rendering && renderedPng == ''){
                rendering = true;
                html2canvas($('#timeline'),{
                    onrendered:function(canvas){
                        renderedPng = canvas.toDataURL().replace('data:image/png;base64,','');
                        rendering = false;
                    }
                });
            }
            return renderedPng;
        },
        onComplete:function(){
            renderedPng = '';
        },
        onCancel: function(){
            renderedPng = '';
        },
        dataType: 'base64',
        swf: '../static/bin/downloadify.swf',
        downloadImage: '../static/img/camera_icon_32.png?rev=1',
        width: 32,
        height: 32,
        transparent: true,
        append: false
    });
like image 128
monitorjbl Avatar answered Oct 24 '22 11:10

monitorjbl