使用链式 JavaScript Promise 淡化 out/in 图像

Fading out/in images using chained JavaScript Promises

我正在尝试创建一个非JQuery 图片幻灯片,其中图片根据计时器淡出 in/out。经过今天的大量研究,我相信 JavaScript 的 Promise 功能可以做到这一点,但它不太正确......

我的问题是淡入和淡出功能似乎同时发生,所以图像只是闪烁。我正在尝试调整使用 then() 链接函数的许多示例中的一些示例,但显然有些地方是错误的。

我的逻辑是:

  1. 在页面加载时显示初始图像(通过 CSS 规则)
  2. 淡出
  3. 更改背景图片URL
  4. 淡入

我的 online example is here,JavaScript 在这里:

// Background images to show
var arr_Images = [
    'https://cdn.pixabay.com/photo/2015/08/24/12/53/banner-904884_960_720.jpg',
    'https://cdn.pixabay.com/photo/2016/11/19/22/52/coding-1841550_960_720.jpg',
    'https://cdn.pixabay.com/photo/2014/05/27/23/32/matrix-356024_960_720.jpg'
];

var cycleImage = document.getElementById("cycleImage");

// Preload images
for(x = 0; x < arr_Images.length; x++)
{
  var img = new Image();
    img.src = arr_Images[x];
}

function fadeOutPromise(element, nextBgImgUrl) {
    console.log("Fading out");
    return new Promise(function(resolve) {
        var op = 1;  // initial opacity
        var timer1 = setInterval(function () {
            if (op <= 0.1){
                clearInterval(timer1);
                element.style.display = 'none';
                cycleImage.style.backgroundImage = "url('" + nextBgImgUrl + "')";
            }
            element.style.opacity = op;
            element.style.filter = 'alpha(opacity=' + op * 100 + ")";
            op -= op * 0.1;
        }, 100);
        resolve("Faded In");
    });
}

function fadeInPromise(element) {
    console.log("Fading in");
    return new Promise(function(resolve) {
        var op = 0.1;  // initial opacity
        element.style.display = 'block';
        var timer2 = setInterval(function () {
            if (op >= 1){
                clearInterval(timer2);
            }
            element.style.opacity = op;
            element.style.filter = 'alpha(opacity=' + op * 100 + ")";
            op += op * 0.1;
        }, 10); 
        resolve("Faded Out");
    });
}

function slideShow() {

    // Loop background image using array
    var i = 0;
    var delay = 3000;

    // Loop
    let imageLoopTimer = setTimeout(function tick() {

        fadeOutPromise(cycleImage, arr_Images[i]).then(
            fadeInPromise(cycleImage).then(function() {
                i++;
                if ( i >= arr_Images.length) { i = 0; }
                imageLoopTimer = setTimeout(tick, delay);               
            })
        );

    }, delay);

}

slideShow();

有人可以先解释一下哪里出了问题,然后提供解决方案吗?

你快到了。问题是你如何兑现你的承诺。 您打算在淡入淡出功能中做的是:
- 创建承诺
- 以间隔
执行逻辑 - 解决承诺

但是你立即解决了这个承诺,而你应该在 fade 操作完成后解决你的承诺:

function fadeInPromise(element) {
    console.log("Fading in");
    return new Promise(function(resolve) {
        var op = 0.1;  // initial opacity
        element.style.display = 'block';
        var timer2 = setInterval(function () {
            if (op >= 1){
                clearInterval(timer2);
                resolve():  // Fade is done here
            }
            element.style.opacity = op;
            element.style.filter = 'alpha(opacity=' + op * 100 + ")";
            op += op * 0.1;
        }, 10); 
    });
}

淡出也一样

闪烁的另一个提示 如果你想要平滑的效果,你不应该经常改变不透明度。在css中,已经有'transition'属性。所以你应该用转换做这样的事情:
- 显示不透明度为 1
的图像 - 将 opactiy 设置为 0
- 在 ms 之后,更改 url 并将不透明度设置为 1

setInterval() 是 运行 作为后台任务,因此 resolve() 将在 timer2.

初始化后立即触发
  • 它非常类似于 运行 一个 async 操作,但不是 awaiting 它。
  • 或者使用 promises 就像调用一个 function 那个 returns 一个 Promise,但是想在没有 .then() 回调的情况下访问数据

您需要在 if (op >= 1) 部分解决您的承诺,以便在 fadeIn/Out 发生后真正解决它。

检查 this snippet 以获取您的更新版本。 Promise 在 setInterval().

中解决

这里是它的相关 JavaScript 代码作为直接片段:

function fadeOutPromise(element, nextBgImgUrl) {
    console.log("Fading out"+i);
    return new Promise(function(resolve, reject) {
        element.style.opacity = 0;
        setTimeout(() => {
            console.log("Fading out done"+i);
            element.style.backgroundImage = "url('" + nextBgImgUrl + "')";
            resolve();
        }, 1000);
    });
}

function fadeInPromise(element) {
    console.log("Fading in"+i);
    return new Promise(function(resolve, reject) {
        element.style.opacity = 1;
        setTimeout(resolve, 1000);
    });
}

var i = 0;
var delay = 3000;

function slideShow() {

    // Loop background image using array

    // Loop
    let imageLoopTimer = setTimeout(() => tick(), delay);

}

function tick() {

    fadeOutPromise(cycleImage, arr_Images[i]).then(() =>
        fadeInPromise(cycleImage).then(function() {
            i++;
            if ( i >= arr_Images.length) { i = 0; }
            imageLoopTimer = setTimeout(() => tick(), delay);               
        })
    );

}

编辑(使用过渡不透明度)

我有 edited the snippet,现在它可以与不透明度过渡一起使用。