Javascript 设计模式以避免延迟返回的承诺覆盖更快的承诺?

Javascript 设计模式以避免延迟返回的承诺覆盖更快的承诺?,javascript,asynchronous,promise,Javascript,Asynchronous,Promise,我正在深入了解如何避免在使用承诺加载图像时出现不必要的行为。我在现实世界中使用大型threejs应用程序非常复杂,因此我在下面将我的问题归结为一个更容易解释的示例 我有一个展示图片的图库分区。有一组缩略图,用户可以单击该缩略图加载与该缩略图关联的图像,加载后在真实应用程序的gallery div中显示。此处使用承诺,因为我们必须加载图像,然后加载后从图像创建纹理,然后再将该纹理传递回应用于平面 我遇到的问题是,如果用户快速单击多个缩略图,它们将按加载顺序应用到gallery div,这可能意味着

我正在深入了解如何避免在使用承诺加载图像时出现不必要的行为。我在现实世界中使用大型threejs应用程序非常复杂,因此我在下面将我的问题归结为一个更容易解释的示例

我有一个展示图片的图库分区。有一组缩略图,用户可以单击该缩略图加载与该缩略图关联的图像,加载后在真实应用程序的gallery div中显示。此处使用承诺,因为我们必须加载图像,然后加载后从图像创建纹理,然后再将该纹理传递回应用于平面

我遇到的问题是,如果用户快速单击多个缩略图,它们将按加载顺序应用到gallery div,这可能意味着用户可以单击要加载的大型图像,然后是一个小图像,导致显示小图像,但随后被较大的图像覆盖,即使它不是最后选择的图像,因为它较大,因此加载时间较长


我不知道如何优雅地解决这个问题,希望有人能就其他软件/程序如何处理这个问题提出建议。是否像使用冗余系统一样简单,以查看图像加载后是否仍被选中,如果未被选中则中止?

有许多不同的算法用于处理此问题,选择过程的一部分取决于您想要的行为。根据您的描述,听起来您希望一个图像在加载后立即显示,但永远不要覆盖它之后出现的并且已经显示的图像。这意味着,如果按照顺序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;
}

如果您不希望lastShownImage或sequenceNumber像这样具有开放作用域,那么可以将它们封装在IIFE或您创建的类的实例中,但由于我不知道您将如何从代码中使用它,也不知道您是否需要更通用的多实例实现,我没有为此增加任何额外的复杂性。

只是防止在加载图像的过程中调用该函数。这可以通过在请求开始时设置标志来实现,然后在请求完成后更新标志。。。。这很有道理。试图通过更新一个文本标志来解决此作业是草率的作业。假设你的承诺在无限期内没有得到解决或拒绝。在此期间,如果结束,您的标志将停留在false,您不能再提出任何请求。不这不是你想要的。看一看关于取消以前承诺的类似主题。最简单方法的可能重复是存储一个滚动取消令牌,从而允许在创建新承诺之前取消以前的承诺。