js异步处理历程

时间:2023-03-09 17:45:54
js异步处理历程

为什么会出现异步:

  js执行环境是单线程的,异步处理就非常重要。

处理的方法:

方法一:callback hell

解决:解决了异步处理

存在问题:出现多个回调函数嵌套,代码就会比较乱,出现回调地狱现象

方法二:Promise

解决:Promise的写法只是回调函数的改进,使用then方法,只是让异步任务的两段执行更清楚而已。

存在问题:Promise的最大问题是代码冗余,请求任务多时,一堆的then,也使得原来的语义变得很不清楚。

方法三:Generator

特征:有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态。

理解:

  调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,必须调用遍历器对象的next方法,使得指针移向下一个状态。

  也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。

  换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行

解决:Generator函数的机制更符合我们理解的异步编程思想

存在问题:流程管理却不方便

方法四:async/await

解决:ES8引入了async函数,使得异步操作变得更加方便。简单说来,它就是Generator函数的语法糖。

——————————————————

需求一:利用上面四种方法完成需求:

  图片一加载完之后加载图片二,
  图片二加载完之后加载图片三,
  图片三加载完之后加载图片四;

图片地址:

    url1 = 'http://es6.ruanyifeng.com/images/cover_thumbnail_3rd.jpg';
url2 = 'http://pic22.nipic.com/20120621/1628220_155636709122_2.jpg';
url3 = 'http://file27.mafengwo.net/M00/5E/6E/wKgB6lPrJiiAFqFIAA1ZCe9u3vo07.jpeg';
url4 = 'http://img2.imgtn.bdimg.com/it/u=1198844836,3147847928&fm=26&gp=0.jpg';

方法一:callback hell

   function getImage(url,success,fail){
let img = document.createElement('img');
img.src = url;
img.onload = function () {
success(img);
}
img.onerror = function () {
fail();
}
}
//加载图片一
getImage(url1,(img)=>{
console.log('图片一',img.width);
//加载图片二
setTimeout(()=>{
getImage(url2,(img)=>{
console.log('图片二',img.width);
//加载图片三
setTimeout(()=>{
getImage(url3,(img)=>{
console.log('图片三',img.width);
//加载图片四
setTimeout(()=>{
getImage(url4,(img)=>{
console.log('图片四',img.width); })
},100) })
},100) })
},100) },()=>{
console.log('失败')
})

方法二:Promise

    function getImage(url) {
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = url;
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject();
}
})
}
//方法一:
getImage(url1).then((img)=>{
console.log('图片一',img.width);
setTimeout(()=>{
getImage(url2).then((img)=>{
console.log('图片二',img.width); setTimeout(()=>{
getImage(url3).then((img)=>{
console.log('图片三',img.width); setTimeout(()=>{
getImage(url4).then((img)=>{
console.log('图片四',img.width);
});
},100)
});
},100)
});
},100) }).catch(()=>{
console.log('失败')
}) //方法二:
getImage(url1).then((img)=>{
console.log('图片一',img.width);
return getImage(url2) }).then((img)=>{
console.log('图片二',img.width)
return getImage(url3)
}).then((img)=>{
console.log('图片三',img.width)
return getImage(url4)
}).then((img)=>{
console.log('图片四',img.width)
}).catch(()=>{
console.log('失败')
})

方法三:Generator

    function getImage(url) {
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = url;
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject();
}
})
}
function * getUrl() {
yield getImage(url1).then((img)=>{
console.log('图片一',img.width);
});
yield getImage(url2).then((img)=>{
console.log('图片二',img.width);
});
yield getImage(url3).then((img)=>{
console.log('图片三',img.width);
});
return getImage(url4).then((img)=>{
console.log('图片四',img.width);
});
} var gU = getUrl();
//存在问题:为什么不是按照顺序打印的?
gU.next();
gU.next();
gU.next();
gU.next();

方法四:async/await

    function getImage(url) {
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = url;
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject();
}
})
} document.onclick = async function() { //捕获错误的情况
try{
let img1 = await getImage(url1)
console.log(img1.width); let img2 = await getImage(url2)
console.log(img2.width) let img3 = await getImage(url3)
console.log(img3.width) let img4 = await getImage(url4)
console.log(img4.width)
}catch (e) {
console.log('图一加载失败');
}
}

——————————————————

需求二:利用Promise和async完成需求:

  图片一、二、三加载完之后加载图片四;

方法一:Promise

    function getImage(url) {
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = url;
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject();
}
})
}
Promise.all([getImage(url1),getImage(url2),getImage(url3)]).then((imgUrl)=>{
console.log(imgUrl);
imgUrl.forEach((item)=>{
console.log(item.width)
})
getImage(url4).then((img)=>{
console.log('图片四',img.width);
})
})

方法二:async/await

    function getImage(url) {
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = url;
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject();
}
})
} document.onclick = async function() {
//捕获错误的情况
try{
let imgUrl = await Promise.all([getImage(url1),getImage(url2),getImage(url3)]);
imgUrl.forEach((item)=>{
console.log(item.width)
}) let img4 = await getImage(url4)
console.log(img4.width)
}catch (e) {
console.log('加载失败');
}
}

参考文章:https://blog.csdn.net/web_csdn_share/article/details/80094779