javascript: 从字节数组创建图像资源

javascript: create an image resource from a byte array

我有一个网页,里面塞满了 javascript,还有一些资源参考资料,例如供 javascript 使用的图像。我使用 websocket 与服务器通信; javascript 解析套接字的数据并相应地处理页面显示。一切正常,除非它不正常。

问题似乎是该页面包含我想在 javascript 控制下显示其部分内容的图像。无论我如何使用 defer,在 javascript 尝试使用图像之前,图像似乎都没有完全下载的情况很明显。结果是在呈现页面时图像丢失,有一小部分时间。

我不太习惯无法严格控制何时发生什么的语言和协议,因此服务器和浏览器以不受控制和异步的顺序传送和执行内容让我很烦。所以我想停止依赖像延迟这样明显不可靠的技巧。我想做的就是下载整个页面,然后打开我的 websocket 并通过它 发送我的图像和其他资源。当该过程完成时,我将知道可以安全地接受来自 websocket 的其他命令并继续执行页面的操作。换句话说,我想颠覆浏览器对资源的异步处理,并在 javascript 控制下串行处理。

从服务器向套接字传输图像文件很容易,而且我可以毫不费力地想出执行此操作的协议。将数据捕获为字节数组也很容易。

但是如何将它们解释为图像?

我知道这种方法有缺点。我不会得到我的图像的浏览器缓存,并且初始页面不会加载得那么快。我没意见。我只是厌倦了 95% 的工作解决方案,不得不怀疑我所做的是否适用于所有可以想象的浏览器。 (从 IE 8 到明年的 Chrome 的所有工作对我来说都是一项要求。)

这种方法可行吗?是否有更好的方法来严格、便携地控制资源加载?

你还没有很明确地知道除了图片之外你在等待什么资源,但是如果它们都是图片,那么你可以使用这个 loadMonitor 对象来监控 N 个图片何时完成加载:

function loadMonitor(/* img1, img2, img3 */) {
    var cntr = 0, doneFn, self = this;

    function checkDone() {
        if (cntr === 0 && doneFn) {
            // clear out doneFn so nothing that is done in the doneFn callback
            // accidentally cause the callback to get called again
            var f = doneFn;
            doneFn = null;
            f.call(self);
        }
    }

    function handleEvents(obj, eventList) {
        var events = eventList.split(" "), i;

        function handler() {
            --cntr;
            for (i = 0; i < events.length; i++) {
                obj.removeEventListener(events[i], handler);
            }
            checkDone();
        }

        for (i = 0; i < events.length; i++) {
            obj.addEventListener(events[i], handler);
        }
    }

    this.add = function(/* img1, img2, img3 */) {
        if (doneFn) {
            throw new Error("Can't call loadMonitor.add() after calling loadMonitor.start(fn)");
        }
        var img;
        for (var i = 0; i < arguments.length; i++) {
            img = arguments[i];
            if (!img.src || !img.complete) {
                ++cntr;
                handleEvents(img, "load error abort");
            }
        }
    };

    this.start = function(fn) {
        if (!fn) {
            throw new Error("must pass completion function as loadMonitor.start(fn)");
        }
        doneFn = fn;
        checkDone();
    };

    // process constructor arguments
    this.add.apply(this, arguments);
}

// example usage code

var cardsImage = new Image();
cardsImage.src = ...

var playerImage = new Image();
playerImage.src = ...

var tableImage = new Image();

var watcher = new loadMonitor(cardsImage, playerImage, tableImage);
// .start() tells the monitor that all images are now in the monitor
// and passes it our callback so it can now tell us when things are done
watcher.start(function() {
    // put code here that wants to run when all the images are loaded
});

// the .src value can be set before or after the image has been 
// added to the loadMonitor
tableImage.src = ...

请注意,您必须确保放入 loadMonitor 的所有图像都得到了 .src 分配,否则 loadMonitor 将永远不会调用其回调,因为该图像永远不会完成。

工作演示:http://jsfiddle.net/jfriend00/g9x74d2j/