ES6学习(如何在循环中使用异步)

55 阅读3分钟

Js的异步方法

Promise

基础用法

1、有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败); 2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。 3、Promise 有 then 和 catch 但是是没有 finally的。

var promise = new Promise((resolve, reject) => {
    return resolve({
        a: 1
    });
});
promise.then((res) => {
    if (res.a === 1) {
        throw "出错了";
    }
}).catch((err) => {
    console.log(err);
    // 出错了
});

Promise.all()

传入多个Promise 等待全部完成之后返回数据, 有一个报错就会直接返回报错不会等别的完成。

function createPromise(time, open) {
    return new Promise((resolve, reject) => {
        if (open) {
            setTimeout(() => {
                resolve(1)
                console.log('open', time)
            }, time)
        } else {
            setTimeout(() => {
                reject(1)
                console.log('close', time)
            }, time)
        }
    })
}
Promise.all([
    createPromise(1000, true),
    createPromise(100,false),
    createPromise(200, true)
]).then((res) => {
    console.log(res)
}).catch((err) => {
    console.log('err', err)
})

Promise.race()

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

// 这个方法会按完成顺序一个一个打印完成的结果
(function () {
    function createPromise(time, id) {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({
                    time,
                    id
                })
            }, time)
        }).catch(() => {
            return {time, id}
        })
    }
    let list = [], len = 0;
    while (len <= 10){
        list.push({
            id: len,
            p: createPromise(500 * len, len)
        });
        len++;
    }
    function initRace() {
        return Promise.race(list.map(item => item.p)).then(({ time, id }) => {
            console.log('触发-id:', id);
            const index = list.findIndex(item => item.id === id);
            if (index !== -1) {
                list.splice(index, 1)
            }
            console.log(list);
            if (list.length > 0) {
                initRace();
            }
        })
    }
    initRace();
})();

Promise.allSettled()

一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作。

const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);

const allSettledPromise = Promise.allSettled([resolved, rejected]);

allSettledPromise.then(function (results) {
  console.log(results);
});

// [
//    { status: 'fulfilled', value: 42 },
//    { status: 'rejected', reason: -1 }
// ]

Promise.any()

只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。

Promise.any()Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。

Promise.resolve() / Promise.reject()

有时需要将现有对象转为 Promise 对象,Promise.resolve()/reject()方法就起到这个作用。

遍历方法

Javascript 遍历方法有, forEach、map、for (for in, for of , for, for await of)、while。

forEach 和 map 方法是不支持异步写法的,内部也不支持 await 等待的写法。

forEach、map

这两个循环方法是不支持异步的。

因为 forEach 和 map 是依赖于 while 结合 callback 方式来执行函数。 比如:

while(index < arr.length){
  callback(item, index)
}

await 并不会等待 callback 的执行,所以对于forEach 和 map 会同时创建多个异步函数但是不会等待它们执行完毕后继续执行下一步。

for 循环

async function createForAsync(){
  let arr =[3,2,1]
  for(let i = 0; i < arr.length; i++){
    const res = await fetch(arr[i])    
    console.log("end")
  }
  console.log('xxxx')
}

function fetch(x){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      console.log(x)
      resolve(x)
    }, 1000 * x)
  })
}
createForAsync()

for of 同上。

对于 for-await-of 会按列表依次等待下一个Promise对象变为resolved状态才进入下一步,具体如下(谁先完成不一定, 区别于forEach和map,这个会等正在处理的是否完成)。

function timeOut(time) {
   return new Promise(function (resolve, reject) {
    setTimeout(function () {
     resolve(time)
    }, time)
   })
  }
  async function test() {
   let arr = [timeOut(2000), timeOut(1000), timeOut(3000)]
   for await (let item of arr) {
    console.log(Date.now(), item)
   }
  }
  test()
    // 1705326968638 2000   时间相同
    // 1705326968638 1000   时间相同
    // 1705326969638 3000   多1秒

while

同 for 循环一样使用即可。

async function createForAsync(){
  let arr =[3,2,1]
  while (arr.length > 0) {
      await fetch(arr.pop())
  }
}

function fetch(x){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      console.log(x)
      resolve(x)
    }, 1000 * x)
  })
}
createForAsync()
// 休息1s - 1
// 休息2s - 2
// 休息3s - 3

其他方法

map 方法

map 方法是不能进行异步操作的

function createPromise(x){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      console.log(x * 10)
      resolve(x * 10)
    }, 1000 * x)
  })
}
const as1 = [1,2,3].map(async (item) => {
    const result = await createPromise(item)
    return result
});
console.log(as1);
// [Promise, Promise, Promise]
// 所以async await 并不生效

当然想进行异步可以先批量生成 Promise 之后用 Promise.All 去处理。