一、异步函数与同步函数的操作顺序 例子1:异步爸爸和异步儿子、同步儿子的故事 async function myAsync(){ timer= await setInterval(()=>{ console.log(count) count++; if(count>10){clearInterval(timer)} console.log("我是异步") },100) console.log("我是同步") }
if和console.log()是属于同一级别的,但是因为if里面有异步函数,所以比同步慢执行; 例子2:异步爸爸和异步儿子,与同步兄弟的故事 async function myAsync(){ timer= await setInterval(()=>{ console.log(count) count++; if(count>10){clearInterval(timer)} console.log("我是异步") },100) console.log("我是同步1") } myAsync() console.log("我是同步2")
console.log("同步2")与myAsync是同一级,但是myAsync是异步函数,所以先输出同步2,又因为例子1说明的原因,所以再输出同步1,最后执行我是异步。 例子3:同步爸爸与异步儿子,与同步兄弟的故事 function myAsync(){ timer= setInterval(()=>{ console.log(count) count++; if(count>10){clearInterval(timer)} console.log("我是异步") },100) console.log("我是同步1") } myAsync() console.log("我是同步2")
此时由于myAsync与console.log()都是同一级别的,所以遵循从上到下执行,又因为myAsync的儿子是异步,所以myAsync的儿子最慢执行。 例子4: async function myAsync1(){ timer= setInterval(()=>{ console.log(count) count++; if(count>10){clearInterval(timer)} console.log("我是异步1") },100) } async function myAsync2(){ setTimeout(()=>{ console.log("我是异步2") },100) } myAsync1() myAsync2() console.log("我是同步2") 同样,同步最先执行,两个异步都是同级,按时间触发顺序,执行
把例子4的两个异步调一下个: async function myAsync1(){ timer= setInterval(()=>{ console.log(count) count++; if(count>10){clearInterval(timer)} console.log("我是异步1") },100) } async function myAsync2(){ setTimeout(()=>{ console.log("我是异步2") },100) } myAsync2() myAsync1() console.log("我是同步2")
根据上面几个例子说明: (1)同一级别下,同步异步执行顺序都是同步函数最先执行,异步函数最慢执行 (2)而两个一样的异步函数,按照顺序,上面的先执行,下面的慢执行 (3)两个不一样的异步函数,要比较异步函数内部是否有继续嵌套异步,还是嵌套同步,有同步的先执行; (4)两个一样的异步执行函数,但是时间触发不一样的,按照时间触发先后,按顺序执行,这也就是实际开发中,你并不知道你向服务器索取的资源哪一个先拿到。先拿到资源的,就先执行,但是这个时间是未知的。 ------------------------------------------------------------------------------------------------------------------------------------------开始讲些有用的: 写个例子: let arr1 = [] function myAsync(){ setTimeout(()=>{ return arr1.push(1);//对数组赋值 },1000) } let num = myAsync(); console.log(num); 运行结果:
答案很明显,赋值时由于异步函数setIterval还没操作,就赋值了,明显赋了个寂寞,所以undefined; 那么早期的时候,我们是怎么拿到异步函数里面的值的呢?
二、早期与异步函数的爱恨情仇: 利用回调函数!看下面这个例子: let arr1 = [] function myAsync(callback){ setTimeout(()=>{ return callback(arr1.push(1));//对数组赋值 },1000) } 传入一个参数callback,这个参数其实就是一个函数,那么怎么取值? // 箭头函数写法 myAsync((arg)=>{ console.log(arg);//arg为参数,其实就是拿到了arr1.push里面的内容 }) //es5写法 myAsync(function callback(arg){ console.log(arg) })
执行顺序分析:首先执行myAsync(),执行完毕后回调callback(),开始执行,这就是所说的回调函数,说白了就是先执行myAsync(),接着执行callback,如何callback内部把内容输出。所以拿到值的其实是callback帮忙拿到的。
有了上面这个思路,所以我们的前辈们很开心,找到了探索新世界的大门,用之而来请求网络数据时非常开心,因为可以拿到异步操作里面的值了!
然而开心了没多久,开始难过了,此时出现了一个怪物:
他叫回调地狱,为什么会有它呢,其实实际应用场景需要先完成第一个异步任务,才能执行第二个异步任务,接着才能完成第三个异步任务,具体例子我现在还没想到,知道的可以评论一下,因为我是个菜鸡。 接着你看一下下面这个例子: async function myAsync1(callback){ setTimeout(()=>{ callback(arr1.push("任务1,我需要最先完成")) },1000) } async function myAsync2(callback){ setTimeout(()=>{ callback(arr1.push("任务2,我需要第二完成")) },1000) } async function myAsync3(callback){ setTimeout(()=>{ callback(arr1.push("任务3,我需要最慢完成")) },1000) } function totalTasks(){ myAsync1(cb1=>{ // 若cb1非空,就是cb1初始化了,可以操作cb1了,专业点说法就是它加载入内存了,,才能继续下面执行cb2,,下面依次类推 if(cb1){ console.log(arr1) myAsync2(cb2=>{ if(cb2){ console.log(arr1) myAsync3(cb3=>{ if(cb3){ console.log(arr1); } }) } }) } }) } totalTasks() 结果:
这还是仅仅三层回调,那么要是多层回调,再写成网络请求格式的,你会写到一半自己线绕晕了。 所以前辈们写这个的时候表情是这样子的:
想拉屎,但是又拉不出来的感觉。 三、promise救世主的出现
愚笨而又可爱的人类啊,我来拯救你们啦: 此时我们只要这样写就好了: async function myAsync(){ return await new Promise(res=>{ setTimeout(()=>{ arr1.push(1) res(arr1) },100) }) } let p = myAsync() p.then((data)=>{ console.log(data) }) promise呢,其实也是用的回调的思想,但是他这种语法格式我们用起来理解就简单多了,维护起来也方便。 它执行的原理就是回调,他其实有两个参数,第一个参数是resolve,表示成功取到值的操作,第二个,表示请求被拒绝的操作,这两个参数也都是回调函数。 下面看个例子,讲一下里面的各个参数的作用: new Promise( function (resolve, reject) { // 一段耗时的异步操作 resolve('成功') // 数据处理完成 // reject('失败') // 数据处理出错 } ).then( (res) => {console.log(res)}, // 成功 (err) => {console.log(err)} // 失败 ) resolve(参数),如果数据请求成功,它会把参数发给then,以备进行下一步操作,reject(参数),如果数据请求错误,他会把参数传给then以备下一步操作。 而then函数它其实也是一个promise函数,它的两个参数作用也一样,then函数可以传给下一个then函数,子子孙孙无穷尽也。 形如: new Promise( function (resolve, reject) { // 一段耗时的异步操作 resolve('成功') // 数据处理完成 reject('失败') // 数据处理出错 } ).then( (res) => {console.log(res)}, // 成功 (err) => {console.log(err)} // 失败 ).then( (res) => {console.log(res)}, // 成功 (err) => {console.log(err)} // 失败 ).then( (res) => {console.log(res)}, // 成功 (err) => {console.log(err)} // 失败 ).then( (res) => {console.log(res)}, // 成功 (err) => {console.log(err)} // 失败 ) 其实还有一个catch函数,它的作用相当于then函数的第二个参数,也相当于promise的第二个参数,都是用来处理错误操作的: new Promise( function (resolve, reject) { // 一段耗时的异步操作 resolve('成功') // 数据处理完成 // reject('失败') // 数据处理出错 } ).then( (res) => {console.log(res)}, // 成功 (err) => {console.log(err)} // 失败 ).catch{ console.log(err) } 具体为什么多次一举,加个catch,因为前面的then函数已经可以处理错误操作了,网上说还是可能异步引起的错误,有些错误只有catch才能发现,这个等我变成大神后再说下原因。 四、promise,与async 与await实现异步操作按顺序执行: // 2.await async 与promise async function myAsync1(){ return await new Promise(res=>{ setTimeout(()=>{ console.log("任务1") res("任务1") },1000) }) } async function myAsync2(){ return await new Promise(res=>{ setTimeout(()=>{ console.log("任务2") res("任务2") },10) }) } async function myAsync3(){ return await new Promise(res=>{ setTimeout(()=>{ console.log("任务3") res("任务3") },1) }) } async function totalTask(){ await myAsync1(); await myAsync2(); await myAsync3(); } totalTask()
直接用async 与await实现异步函数顺序执行。 注:async与await关系密切,只有声明了async的函数,里面才能使用await。await作用就是等待这个函数执行,等待执行完再执行下一个。
好了,写到这里了,我好帅啊!
async function myAsync1(){
timer= setInterval(()=>{
console.log(count)
count++;
if(count>10){clearInterval(timer)}
console.log("我是异步1")
},100)
}
async function myAsync2(){
setTimeout(()=>{
console.log("我是异步2")
},100)
}
myAsync1()
myAsync2()
console.log("我是同步2")
|
|
来自: python_lover > 《待分类》