设计模式避免迟到的承诺覆盖更快的承诺?

时间:2018-05-02 00:21:27

标签: javascript asynchronous promise

我正在深入了解如何使用promises加载图像时避免不必要的行为。我的实际使用非常复杂(一个大型的三个应用程序)所以我把我的问题归结为一个更容易解释的例子。

我有一个展示图像的图库div。用户可以点击一组缩略图,加载与该缩略图相关联的图像,一旦加载就显示在图库div中(在实际应用中,我们必须使用承诺,因为我们必须加载图像,然后加载后创建一个在将纹理传回去应用于平面之前从中获取纹理。)

我遇到的问题是,如果用户快速点击多个缩略图,则会按照加载的顺序将其应用于图库div,这可能意味着用户可以点击要加载的大图片,然后会生成一个小图片显示的小图像然后被较大的图像覆盖(即使它不是最后选择的,因为它更大,因此加载时间更长)。

我对如何优雅地解决这个问题感到茫然,并希望有人能够就其他软件/程序如何处理这个问题提出建议。它是否像拥有冗余系统一样简单,以便在图像加载后仍然可以选择图像,如果图像不是则中止?

1 个答案:

答案 0 :(得分:1)

有许多不同的算法可以解决这个问题,选择过程的一部分取决于你想要的行为。根据您的描述,听起来您希望图像在加载后立即显示,但永远不会覆盖后面的图像并且已经显示。这意味着如果按顺序1,2,3请求图像,但按2,1,3的顺序到达,那么您将显示图像2,然后显示3并且从不显示1.

假设这是所需的算法,那么一种相当简单的处理方法就是为每个请求分配一个序列号,然后跟踪你显示的最后一个序列号。每当任何图像完成加载时,您检查它的序列号是否显示在最后一个序列之上。如果没有,您就不会显示它,因为它是旧图像被新图像超越的图像。如果是,则显示它并将lastShownSequence数字更新为此图像的序列号。这种类型的算法需要两个持久变量来跟踪lastShownSequence数和要分配的nextSequenceNumber。

以下是示例代码实现:

var lastShownImage = 0;
var nextSequenceNumber = 1;

// url is image url
// elem is image element in the page to replace with newly loaded image element
function loadImage(url, elem) {
    let imageSequenceNumber = nextSequenceNumber++;
    let img = new Image();
    img.onload = function() {
        // image loaded now
        // see if we should display it or not
        if (imageSequenceNumber > lastShownImage) {
            // hide current image so there's never any flashing of two images
            elem.style.display = "none";
            // record the sequence number we are showing
            lastShownImage = imageSequenceNumber;
            // insert new image
            let parent = elem.parentNode;
            parent.insertBefore(img, elem);
            // remove previous image
            parent.removeChild(elem);
        }
    };
    img.src = url;
}

如果您不希望lastShownImagesequenceNumber像这样开放,那么它们可以封装在IIFE或您创建的类的实例中,但是因为我不知道你将如何从你的代码中使用它,或者看看你是否需要一个更通用的多实例实现,我没有为此添加任何额外的复杂性。