美文网首页
JS异步编程最佳实现方法 (附:异步方法如何循环调用)

JS异步编程最佳实现方法 (附:异步方法如何循环调用)

作者: 熊爸天下_56c7 | 来源:发表于2020-12-25 10:06 被阅读0次

    目前来说,JS实现异步编程的最好方法还是: ①. Promise , ②. aysnc await方法

    基本原则:
    如果只用Promise, 那异步过程只在Promise里, 如果想执行Promise后返回结果, 那就用 aysnc/await 调用Promise

    Promise 方法

    简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。比如,f1的回调函数f2,可以写成:f1().then(f2);

    aysnc await 方法

    如果,一个函数用async修饰,它return出来的就会是一个promise

    执行函数时, 可以用 await修饰, 用以执行异步函数

    一. 一个生动的Promise例子

    下面这个例子是个非常经典的例子, 忘记了从哪位老铁哪里摘抄的了, 抱歉, 但是感谢!

    //这是个普通函数
    function read() {
      console.log('小明认真读书');
    }
    //这是个异步函数
    function eat() {
      return new Promise((resolve, reject) => {
        console.log('好嘞,吃饭咯');
        setTimeout(() => {
          resolve('饭吃饱啦');
        }, 1000)
      })
    }
    
    //这是个异步函数
    function wash() {
      return new Promise((resolve, reject) => {
        console.log('唉,又要洗碗');
        setTimeout(() => {
          resolve('碗洗完啦');
        }, 1000)
      })
    }
    
    //这是个异步函数
    function mop() {
      return new Promise((resolve, reject) => {
        console.log('唉,还要拖地');
        setTimeout(() => {
          resolve('地拖完啦');
        }, 1000)
      })
    }
    
    //这是个异步函数 但写法和上面不太一样, 其实它是一个Promise对象
    const cooking = new Promise((resolve, reject) => {
      console.log('妈妈认真做饭');
      setTimeout(() => {
        resolve('小明快过来,开饭啦');
      }, 3000);
    })
    
    //程序运行开始:
    //1. 先执行这个异步函数
    cooking.then(msg => {
      console.log(msg);
      return eat();
    }).then(msg => {
      console.log(msg);
      return wash();
    }).then(msg => {
      console.log(msg);
      return mop();
    }).then(msg => {
      console.log(msg);
      console.log('终于结束啦,出去玩咯')
    })
    //2. 再执行这个普通函数
    read();
    

    我们来简单分析一下为什么会这么执行

    1. 程序一开始,我们先执行了cooking
      cooking里有一句console.log('妈妈认真做饭');是立即执行的语句,并不需要异步处理,所以会立即打印
      cooking 里的定时器是需要一定的执行时间的,所以是一个异步方法, 会呆一会才能执行到,后续的.then里的函数都要等这个方法resolve或者reject里才能执行
    2. 但程序不会等他 resolve 而是继续执行
      于是执行到了 read() 所以会打印 小明认真读书
    3. 假设此时cooking的异步方法resolve了, 就会执行.then, 从而触发eat
    4. eat里也是有同步,有异步, 以此类推....

    二. Promise异步带循环

    var tasks = [];
    
    function output(j) {
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          console.log(new Date(), j);
          resolve(j*2);
        }, 1000 * i);
      }).then(j=>{
        console.log("j*2=",j);
      })
    }
    
    for (var i = 0; i < 1000; i++) {
      if (tasks.length < 10) {
        tasks.push(output(i));  //执行顺序:首先在这里将定时器设置好,
      } else {
        break;
      }
      // 也就是循环设置定时器,由于执行时间很快,每次循环的间隔可以忽略不计,
      // 所以可以认为是设置了5个时间分别为0~4s的定时器,已经开始计时。
      // 计时后返回promise对象,放在tasks数组中
    }
    console.log(tasks);
    

    我们打印一下tasks发现: 在程序一开始,他就有了十个Promise子元素, 也就是说for循环和最底部的console.log(tasks);是立即执行的, 这不难理解, 因为它们是同步函数

    但是为什么下面的那些打印如此规整的排列了下来呢?而且时间间隔完全对呢???

    首先: 因为每个元素是按顺序push进去的,所以会按顺序执行每条的output(i), 其次: 每次的output(i)都是异步的,他们形成了一个异步处理队列, 只有上一个异步做完了,下一个异步才会开始

    三. aysnc await方法

    如果,一个函数用async修饰,它return出来的就会是一个promise

    执行函数时, 可以用 await修饰, 用以执行异步函数

    async function test1() {         //因为里面返回的本身就是个promise,所以不用async修饰也可以
        return new Promise(resolve => {
            setTimeout(() => {
                resolve('hola')     //异步执行后,调用resolve()改变异步状态
            }, 3000);
        })
    }
    async function test2() {
        const v = await test1();   //等待异步方法test1执行完成把值传给v
        console.log(v);
    }
    test2();   //执行时,会延时3秒打印 ho'la
    

    四. aysnc await方法实现循环异步

    async function add(i) {         //因为里面返回的本身就是个promise,所以不用async修饰也可以
      return new Promise(resolve => {
        setTimeout(() => {
          resolve(++i)     //异步执行后,调用resolve()改变异步状态
        }, 2000);
      })
    }
    
    async function test3() {
      let count = 0;
      while (count < 10) {
        count = await add(count);   //等待异步方法test1执行完成把值传给v
        console.log(count);
      }
    }
    
    test3()
    

    因为add函数被 await修饰了, 所以count会等待add 的返回值, 返回后才往下进行

    相关文章

      网友评论

          本文标题:JS异步编程最佳实现方法 (附:异步方法如何循环调用)

          本文链接:https://www.haomeiwen.com/subject/vstmnktx.html