使用Deferred解决回调问题

<!doctype html>
<html lang="zh">
<head>
<meta charset="utf-8">
<title>使用Deferred解决回调问题</title>
</head>
<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
let deferred1 = $.Deferred(); // 第1个Deferred对象
let deferred2 = $.Deferred(); // 第2个Deferred对象
let deferred3 = $.Deferred(); // 第3个Deferred对象

// 这里是异步的,必须三个Deferred对象都调用了resolve()才会执行done()
$.when(deferred1, deferred2, deferred3).done(function(name, gender, age) {
    console.log('俺叫' + name + '(' + gender + '),今年' + age + '岁。'); // 俺叫张三(男),今年18岁。
});

// 这里顺序无所谓,但是只要还有一个Deferred对象没有调用resolve()就不会执行上面设置的done()
deferred3.resolve(18); // 第3个Deferred对象调用resolve()
deferred1.resolve('张三'); // 第1个Deferred对象调用resolve()
deferred2.resolve('男'); // 第2个Deferred对象调用resolve()

//========== 总结 ==========//
// 1、当所有Deferred对象都调用了resolve()后就会立即执行done()。
</script>
</body>
</html>

 

<!doctype html>
<html lang="zh">
<head>
<meta charset="utf-8">
<title>图片加载完成后回调</title>
<style type="text/css">
*{margin:0;padding:0;}
li{float:left;display:block;margin:10px;list-style:none;}
img{width:250px;height:auto;}
</style>
</head>
<body>
<ul>
<li><img src="https://gd-hbimg.huaban.com/0baaa30f2c64c01aa7a9282c9aba829b7eaf35c24332a-tzFLxo_fw1200webp" alt=""></li>
<li><img src="https://gd-hbimg.huaban.com/0f5627cb52d09630555c6984fcdbba413bc19ed3780aa-GuY8C8_fw1200webp" alt=""></li>
<li><img src="https://gd-hbimg.huaban.com/1a86098a1b012bf28b88843fff46441c56c8b0b4a47c3-uXHCKe_fw1200webp" alt=""></li>
<li><img src="https://gd-hbimg.huaban.com/1e589bbbc0a18988d6ad6323767b1beba5d26a68ae077-0wUf0V_fw1200webp" alt=""></li>
<li><img src="https://gd-hbimg.huaban.com/3e8b142316fa139244c592d3582dab216d243d882734c-94KnbB_fw1200webp" alt=""></li>
<li><img src="https://gd-hbimg.huaban.com/42b80c9cf61edaa6d73b91faee7302ab0b059f8c1b8a3-ZGvvD4_fw1200webp" alt=""></li>
<li><img src="https://gd-hbimg.huaban.com/43a4ba5ae2bc8d454f94de14d8e825cd20fdfb4adf8b8-5ReQvh_fw1200webp" alt=""></li>
</ul>
<script type="text/javascript" src="./jquery.min.js"></script>
<script type="text/javascript">
let imgs = $('ul > li > img'); // 所有图片
let deferreds = []; // Deferred对象

// 通过延迟执行可以模拟出一部分图片在绑定load和error事件前已经完成加载的情况
setTimeout(function () {
    // 遍历所有图片
    imgs.each(function () {
        // 对尚未完成加载(注:这里的完成包括加载成功和加载失败)的图片绑定load和error事件
        if (!$(this).get(0).complete) {
            let def = $.Deferred();

            $(this).on('load', function () { // 加载成功
                console.log('load + 1  ', Math.random());
                def.resolve();
            }).on('error', function () { // 加载失败
                console.log('error + 1  ', Math.random());
                def.resolve();
            });

            deferreds.push(def);
        }
    });

    // 这里是异步的,必须等deferreds里所有的Deferred对象都调用了resolve()才会执行
    $.when.apply(null, deferreds).done(function () {
        console.log('所有图片加载完成');
    });
}, 150);

//========== 输出结果·开始 ==========
// load + 1   0.38514296932924075
// load + 1   0.5667542539732484
// load + 1   0.8111099284922989
// 所有图片加载完成
//========== 输出结果·结束 ==========

//========== 总结 ==========//
// 1、可以通过开发者工具限制网速,这样能更直观地看到加载流程是怎么样的。
// 2、虽然图片有7张,但是由于代码延迟执行的原因,有些图片在执行到遍历所有图片时就已经加载完成了,这部分图片的complete属性为true所以
//    不会执行到绑定load和error事件的代码,所以输出结果只有三个“load + 1”,事实上就算绑定了也没意义,因为已经加载完成的图片是不会
//    再触发load事件的。
</script>
</body>
</html>

Copyright © 2024 码农人生. All Rights Reserved