Promise的图片异步加载其实就是利用了宏任务先执行,后执行微任务:
new Promise()的时候,Promise新建后就会立即执行
利用这一特性,我们可以创建Promise对象的时候,创建image标签,然后再给img标签的 src赋值路径,这样在then的回调函数中,把其加入到盛放显示图片的盒子中,盒子中原来展示是一个缺省图,等到图片加载好了,就显示真正的图片:
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta http-equiv="X-UA-Compatible" content="IE=edge">
7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <title>Document</title>
9 </head>
10 <style>
11 h1 {
12 display: block;
13 }
14 </style>
15
16 <body>
17 <div id='box'>
18 <h1>我是一张缺省图</h1>
19 </div>
20 </body>
21
22 </html>
23 <style>
24
25 </style>
26 <script>
27 var oBox = document.getElementById('box');
28 var oH = document.querySelector('h1')
29
30 function loadImageAsync(url) {
31 return new Promise(function(resolve, reject) {
32 var image = new Image();
33
34 image.onload = function() {
35 resolve(image);
36 };
37
38 image.onerror = function() {
39 reject(new Error('Could not load image at ' + url));
40 };
41
42 image.src = url;
43 });
44 }
45 // 模拟一下异步加载图片
46 // 用setTimeoutm模拟ajax调用接口,获取接口返回的图片路径,然后传入函数中,函数中已经提前创建好了
47 // 图片标签。我们在.then的回调函数中自行决定插入div容器中做一些事,比如把缺省图隐藏掉
48 setTimeout(() => {
49 loadImageAsync('./lion.jpg').then(res => {
50 oH.style.display = 'none';
51 oBox.appendChild(res);
52 })
53 }, 1000)
54 </script>
1秒后显示图片:
Promise封装ajax
1 function myAxios(url) {
2 return new Promise((resolve, reject) => {
3 let http = new XMLHttpRequest();
4 http.open('GET', url)
5 http.onreadystatechange = function() {
6 if (this.readyState !== 4) {
7 return
8 }
9 if (this.status === 200) {
10 resolve(this.response)
11 } else {
12 reject(new Error(this.txt))
13 }
14 }
15 http.send();
16 })
17 }
18
19 myAxios('').then(res => {
20 // 拿到数据
21 }).catch(err => {
22 // 捕获错误
23 })
Promise的finally原理
finally中的函数无参数的情况:
Promise.prototype.Myfinally = function(callback) { let P = this.constructor; return this.then( // 正常情况 () => P.resolve(callback()), () => P.resolve(callback()) ); }; function promiseFn(flag) { return new Promise((resolve, reject) => { if (flag) { resolve('正确') } else { reject('错误') } }) } promiseFn(false).then(res => { console.log(res, '我是success'); }).catch(err => { console.log(err, "我是err"); }).Myfinally(res => { // console.log(res, '结果'); //不传参,这里就没有res,输出undefined console.log('我是finally'); })
有参数的情况,直接把成功时或者失败时候的参数传给finally的回调函数,这样一个finally中的那一个参数,既可以捕获到失败也可以捕获到成功
Promise.prototype.Myfinally2 = function(callback) { let P = this.constructor; return this.then( // 传参的情况 value => P.resolve(callback(value)), reason => P.resolve(callback(reason)) ); }; function promiseFn2(flag) { return new Promise((resolve, reject) => { if (flag) { resolve('正确') } else { reject('错误') } }) } // 传参就可以用finally方法,finally里面的参数是res,也可以是err promiseFn2(true).Myfinally2((res) => { // res可以是原有的then成功的结果,又可以是catch失败的结果 console.log(res, '我是结果'); })