异步问题
在解释async 函数前,我们先可以看看普通的函数为什么处理不了异步问题
function Myobject (){ setTimeout(()=>{ console.log('1') },100) console.log('2') }
这里需要明确几点:
1.js代码是从上往下执行的.且不出错的情况下会一直执行下去
2.异步产生的原因是浏览器是多线程的.(js线程是单线程)
3.异步问题多是指回调函数.
然后我们在解析一下当这个函数被执行是会怎么样?首先,setTimeout会被执行,也就是说会由定时触发器线程开始计时,但是不会打印,你可以理解为(console.log('1')实际上是计时结束后的回调函数,它由事件触发线程保存,然后由js线程打印'2'.最后事件触发线程把对应的事件交给再交给js线程去执行,最后才打印"1".
这里我们把定时器(定时触发器线程)换成http请求(http请求线程)是一样的.
所以,无论如何,常规的写法都没法避免这个问题.那我们看看以往的异步问题是怎么处理的?
首先是回调函数,也就是说根据不同的状态执行不同的回调函数.但是假如嵌套多层就对代码的观感和维护很不友好.但是,"回调函数"是正解,,不过其有个违和点.就是你先得知道他是异步的,你的同步代码得迁移到回调函数里面,得改成.
function Myobject (){ setTimeout(()=>{ console.log('1') if(条件满足){ console.log('2') } },100) }
Promise,它不进行所谓的嵌套,而是进行链式调用,解决了"回调地狱"问题.但它其实也是一种回调函数,只不过换种方式调用,所以它也一样,你得先意识到他是异步,然后去修改你的代码
这两种方案的特点其实都是,用特殊的方式把函数进行顺序的调用.而且都是完整的函数,这点很重要.同时他不太符合我们的写代码习惯.
Generator 函数
然后我们回到Generator 函数身上,看以下例子
function* helloWorldGenerator() { yield console.log('444'); yield console.log('555'); console.log('33') } var hw = helloWorldGenerator() hw.next() hw.next() hw.next()
它有以下几个特点
1.它看起来就像个多了点奇怪东西的普通函数(目的),
2.它被调用的时候并不会直接执行里面的所有代码.
3.它里面的代码会被分成好几部分,每个部分按顺序且单独执行且可以有返回值.所以我们完全可以根据上一步的执行结果来判断是不是执行下一步.
具体的原理可以单独去查一下
async函数为什么能处理异步函数
首先,async函数是Generator 函数的语法糖,也就是说Generator 函数有的特点它都有,如下
let helloWorldGenerator=async function() { await new Promise((resolve) => { setTimeout(resolve, 1000); }) await console.log('555'); console.log('33') } var hw = helloWorldGenerator()
那么它都做了哪些优化呢?
1.保留了看起来像普通函数的特点
2.把*和yield换成了async和await,语义化,更清晰
3.它不需要我们手动的去调用.next方法了,也就是说它自动帮我们加了判断,以及满足条件去调用下一个.next方法
其结果就是,我们可以像写一般函数那样去写带有异步任务的函数了.
总结,async函数实际上就是利用Generator函数的特性来处理异步问题的.它比起Promise函数,特点是更加符合一般函数的代码书写习惯,它不做函数的管理,而是代码块的管理