• 异步函数与同步函数


    一、异步函数与同步函数的操作顺序

    例子1:异步爸爸和异步儿子、同步儿子的故事

    async function myAsync(){
      timer= await setInterval(()=>{
      console.log(count)
      count++;
      if(count>10){clearInterval(timer)}
        console.log("我是异步")
      },100)
      console.log("我是同步")
    }
    myAsync()

     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,表示成功取到值的操作,第二个,表示请求被拒绝的操作,这两个参数也都是回调函数,如果操作成功,resolve则会执行,并return本身携带的参数;reject亦然。

    下面看个例子,讲一下里面的各个参数的作用:

    new Promise(
      function (resolve, reject) {
        // 一段耗时的异步操作
    settimeout(()=>{
    if(n>10)
    { resolve('成功') // 数据处理完成
    }else{
        reject('失败') // 数据处理出错
    }

    },10000)
    }).then(
      (res) => {console.log(res)},  // 成功
      (err) => {console.log(err)} // 失败
    )

    resolve(参数),如果数据请求成功,它会把参数发给then,以备进行下一步操作,reject(参数),如果数据请求错误,他会把参数传给then以备下一步操作。

    而then函数它其实也是一个回调函数,它的两个参数是用来接收上一个函数传过来的值,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作用就是等待这个函数执行,等待执行完再执行下一个。

    好了,写到这里了,我好帅啊!

    穷则独善其身,达则兼济天下……
  • 相关阅读:
    实验楼挑战赛(1)-实现不可修改字典
    python django前端界面实现数据库数据excel导出
    python2中range和xrange的异同
    python的json模块的dumps,loads,dump,load方法介绍
    ajax500错误
    伪元素小tips
    使用css3制作蚂蚁线
    chardet坑——比蜗牛还慢
    Flask的socket.error:10053
    chrome插件开发-消息机制中的bug与解决方案
  • 原文地址:https://www.cnblogs.com/hmy-666/p/14501990.html
Copyright © 2020-2023  润新知