How to get seamless display in javascript slideshow

题意:在JavaScript幻灯片中如何实现无缝播放

问题背景:

I've written a basic slideshow with javascript. It downloads a randomly-chosen JPEG from a CGI script, scales it down if necessary, deletes the previously-displayed slide and displays the new one on the page, repeating this every two seconds.

我已经用JavaScript编写了一个基本的幻灯片播放程序。它从CGI脚本中随机下载一个JPEG图像,如果需要的话还会缩小它的大小,删除之前显示的幻灯片,并在页面上显示新的幻灯片,每两秒重复一次这个过程。

The problem is that some of the JPEGs are very large (from 3MB to 20MB). The downloading (and, I presume, the scaling) take so long that sometimes, when the previous slide is deleted, several seconds elapse before the next one appears.

问题是有些JPEG图像非常大(从3MB到20MB)。下载(以及我猜想的缩放)需要很长时间,以至于有时在删除前一个幻灯片后,需要等待几秒钟才能看到下一个幻灯片出现。

I'm sure this is because of the asynchronous nature of the processing, but I don't know how to control it. What I'd like is for each slide to appear for a minimum of two seconds or long enough that the next slide will appear without any delay.

我确定这是因为处理过程的异步性质,但我不知道如何控制它。我希望的是每个幻灯片至少出现两秒钟,或者足够长的时间,以便下一个幻灯片能够无延迟地出现。

(I'm using a placeholder image generator in this demo, so I don't know how well it will illustrate the delay problem.)

(我在这个演示中使用了一个占位符图像生成器,所以我不知道它能多好地说明延迟问题。)

    function showSlides() {
        const my_img = document.createElement('img');
        fetch('https://picsum.photos/2000/600')
            .then(my_response => my_response.blob())
            .then(my_blob => {
                const my_url = URL.createObjectURL(my_blob);
                my_img.setAttribute('src', my_url);
                my_img.setAttribute('class', 'picture-div-img');
            })
            .catch(my_error => console.error('Error: ', my_error));

        /* NOTE: would like to wait until new slide is completely downloaded
           and rendered offscreen before deleting current slide and displaying
           new one */

        /* Delete current slide */
        const my_parent = document.querySelector('#slide-div');
        while (my_parent.firstChild) {
            my_parent.removeChild(my_parent.firstChild);
        }
        /* Insert new slide */
        my_parent.appendChild(my_img);
        setTimeout(showSlides, 2000); /* Change image every 2 seconds */
    }
    html {
        height: 100%;
        width: 100%;
    }

    body {
        /* prevent body from displacing */
        margin: 0;
        /* body should perfectly superimpose the html */
        height: 100%;
        width: 100%;
    }

    .outer-div {
        display: flex;
        flex-flow: column;
        height: 100%;
        /* Now create left/right margins */
        margin: 0 0.5em;
    }

    .inner-fixed-div {
        margin-top: 0.5em;
    }

    .inner-remaining-div {
        margin-bottom: 1em;
        flex-grow: 1;
        /* hints the contents to not overflow */
        overflow: hidden;
    }

    .picture-div {
        /* force the div to fill the available space */
        width: 100%;
        height: 100%;
    }

    .picture-div-img {
        /* force the image to stay true to its proportions */
        width: 100%;
        height: 100%;
        /* and force it to behave like needed */
        object-fit: scale-down;
        object-position: center;
    }
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

</head>

<body onload="showSlides();">
  <div class="outer-div">
    <div class="inner-fixed-div">
      <h1>Lorem Ipsum</h1>
    </div>
    <div class="inner-remaining-div">
      <!-- This div will hold the <img> -->
      <div id="slide-div" class="picture-div">
      </div>
    </div> <!-- end of inner-remaining-div -->
  </div> <!-- end of outer-div -->
</body>
</html>

问题解决:

Perhaps what you really want is to wait 2 seconds after getting the image then repeat. Here we use a promise timer borrowed from this answer What is the JavaScript version of sleep()? - Stack Overflow to do so;

也许你真正想要的是在获取图像后等待2秒钟,然后再重复。在这里,我们使用了一个从Stack Overflow的“JavaScript版本的sleep()是什么?”这个问题的答案中借来的promise定时器来实现这一点;

No need to remove and insert, just update the source.

无需删除和插入,只需更新源即可。

const sleep = ms => new Promise(r => setTimeout(r, ms));

async function showSlides(duration) {
  const my_parent = document.querySelector('#slide-div');
 // let mySource = "";
  const my_img = document.createElement('img');
  my_img.setAttribute('class', 'picture-div-img');
  my_parent.appendChild(my_img);
  fetch('https://picsum.photos/2000/600')
    .then(my_response => my_response.blob())
    .then(my_blob => {
     let mySource = URL.createObjectURL(my_blob);
      sleep(duration).then(() => {
        my_parent.querySelector('img').src = mySource;
        showSlides(duration);
      });
    })
    .catch(my_error => console.error('Error: ', my_error));
}
showSlides(2000);
html {
  height: 100%;
  width: 100%;
}

body {
  /* prevent body from displacing */
  margin: 0;
  /* body should perfectly superimpose the html */
  height: 100%;
  width: 100%;
}

.outer-div {
  display: flex;
  flex-flow: column;
  height: 100%;
  /* Now create left/right margins */
  margin: 0 0.5em;
}

.inner-fixed-div {
  margin-top: 0.5em;
}

.inner-remaining-div {
  margin-bottom: 1em;
  flex-grow: 1;
  /* hints the contents to not overflow */
  overflow: hidden;
}

.picture-div {
  /* force the div to fill the available space */
  width: 100%;
  height: 100%;
}

.picture-div-img {
  /* force the image to stay true to its proportions */
  width: 100%;
  height: 100%;
  /* and force it to behave like needed */
  object-fit: scale-down;
  object-position: center;
}
<div class="outer-div">
  <div class="inner-fixed-div">
    <h1>Lorem Ipsum</h1>
  </div>
  <div class="inner-remaining-div">
    <div id="slide-div" class="picture-div">
    </div>
  </div>
</div>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

营赢盈英

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值