1、什么是异步
2、异步进化史
回调函数 —> Promise —> Generator —> async/await。
3、同步异步举例
// 异步 (callback 回调函数)console.log(100)setTimeout(function(){console.log(200)},1000)console.log(300)//100//300//200// 同步console.log(100)alert(200)console.log(300)//100//200//300
4、异步应用场景
4.1 网络请求,如ajax图片加载
// ajaxconsole.log('start')$.get('./data1/json',function(data1){console.log(data1)})console.log('end')
4.2 定时任务,如setTimeout
//图片加载console.log('start')let img = document.createElement('img')img.onload = function(){console.log('loaded')}img.src = '/xxx.png'console.log('end')
4.3 事件监听、绑定
// 事件监听document.getElementById('#myDiv').addEventListener('click', function (e) {console.log('我被点击了')}, false);
5、回调地狱
当回调只有一层的时候感觉没有什么问题,但是一但嵌套层级过多,代码可读性和可维护性就变差。
const https = require('https');https.get('目标接口1', (res) => {console.log(data)https.get('目标接口2', (res) => {https.get('目标接口3'), (res) => {console.log(data)https.get('目标接口4', (res) => {https.get('目标接口5', (res) => {console.log(data).....// 无尽的回调}}}}})
6.典型题
6.1 同步与异步的区别
- 基于JS是单线程语言
- 异步不会阻塞代码执行
- 同步会阻塞代码执行
6.2 异步加载图片
function loadImg(src){return new promise((resolve,reject)=>{const img = document.createElement('img')img.onload = () => {resolve(img)}img.onerror=() => {reject(new Error(`图片加载失败`))}img.src = src})}const url1 = 'xxx'const url2 = 'xxx'loadImg(url).then(img=>{console.log(img1.width)return img1 //普通对象}).then(img1=>{console.log(img.height)return loadImg(url2) //promise实例}).then(img2=>{console.log(img2.height)}).catch(ex=>console.log(ex))
6.3 setTimeout场景题
// setTimeout笔试题console.log(1)setTimeout(function(){console.log(2)},1000)console.log(3)setTimeout(funcion()=>{console.log(4)},0)console.log(5)//1 3 5 4 2
6.4 回调函数有什么缺点?如何解决回调地狱问题?
回调函数有一个致命的弱点,就是容易写出回调地狱(Callback hell)。假设多个请求存在依赖性,你可能就会写出如下代码:
ajax(url, () => {// 处理逻辑ajax(url1, () => {// 处理逻辑ajax(url2, () => {// 处理逻辑})})})
回调地狱的根本问题就是:
- 嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身
- 嵌套函数一多,就很难处理错误
当然,回调函数还存在着别的几个缺点,比如不能使用 try catch 捕获错误,不能直接 return。
解决方法:使用Promise;
