forEach循环如何才能在回调函数完成再进行下次循环?

  • 23
 res.forEach(it => {
          if (it.printType == 0 || it.printType == 1) {
                 clearInterval(this.scrollTimer);
                 window['extendObj'].printPdf(it.result, function (el) {
                       if (!el) {
                            console.log(完成)
                       } else {
                            console.log(失败)
                       }
                 }, it.printerName, 60, it.printType);
                           
           }
})

看代码!!

回复
阅读 1.7k
4 个回答

首先,需要把 printPdf 封装成 Promise,比如

if (it.printType == 0 || it.printType == 1) {
    return new Promise(resolve => {
        clearInterval(this.scrollTimer);
        window['extendObj'].printPdf(it.result, function (el) {
            if (!el) {
                resolve("完成")
            } else {
                resolve("失败")
            }
        }, it.printerName, 60, it.printType);
    }
}

forEach() 是做不到了,可以自己写个 asyncForEach() 来干:

// 模拟 printPdf
function printPdf(p, cb) {
    const ms = 200 + ~~(Math.random() * 1000);
    setTimeout(() => cb(ms % 2), ms);
}

// 模拟 res
const res = Array.from({ length: 10 }, (_, i) => ({ result: i, printType: i % 3 }));

// 封装扩展一个 asyncForEach,需要每个 callback 返回一个 Promise 来等
Array.prototype.asyncForEach = async function (fn) {
    const length = this.length;
    for (let i = 0; i < length; i++) {
        await fn(this[i], i, this);
    }
};

// 封装 printPdf 为 Promise,别忘了 resolve
res.asyncForEach(it => {
    if (it.printType == 0 || it.printType == 1) {
        return new Promise(resolve => {
            printPdf(it.result, function (el) {
                if (!el) {
                    console.log("完成" + it.result);
                } else {
                    console.log("失败" + it.result);
                }
                resolve();
            });
        });
    }
});

forEach做不到,如果printPdf是一个promise可以使用await..async和for循环实现,如果不是可以使用promise链式调用实现

res.reduce((p, it) => {
    return p.then(res => {
        return new Promise((res, rej) => {
            if (it.printType == 0 || it.printType == 1) {
                 clearInterval(this.scrollTimer);
                 window['extendObj'].printPdf(it.result, function (el) {
                       if (!el) {
                            console.log(完成)
                            res()
                       } else {
                            console.log(失败)
                            rej()
                       }
                 }, it.printerName, 60, it.printType);
                           
           }
        })
    })
}, Promise.resolve())

如果要等待异步调用完成,使用await,不能用forEach和map函数遍历, 即使给循环体函数加上async也是没用的。可以用for/for...in/for...of进行遍历,比如下面这样

// 异步函数
const asyncFunc = () => new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('等待执行了');
        resolve(123);
    }, 1000)
});

const arr = [1,2,3,4];

// 下面3种方式都能等待异步完成
for(const x of arr) {
    await asyncFunc();
    console.log('异步执行完成');
}

for(let i = 0; i < arr.length; i++) {
    await asyncFunc();
    console.log('异步执行完成');
}

for(const x in arr) {
    await asyncFunc();
    console.log('异步执行完成');
}

forEach不行。不过可以构造一个异步迭代器,用for await of 遍历

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏