美文网首页
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