在异步编程中,面对多个异步操作的情况,往往需要用到循环来处理每个异步操作的结果。而 ES8 中引入了一个新的循环结构 for-await-of,可以更方便的处理异步操作的结果,避免了回调地狱的问题。
for-await-of 的用法
for-await-of 语句可以用于遍历异步操作返回的迭代器(Iterator),语法如下:
for await (variable of asyncIterable) { // statements }
其中,asyncIterable 表示一个异步可迭代对象,variable 表示每次迭代时返回的变量。在循环执行时,当异步 promise 对象 resolved 时,for-await-of 会通过 await 操作符将结果返回给 variable 变量,然后执行循环体内的语句。当异步操作全部执行完毕后,for-await-of 循环结束。
for-await-of 的实现
我们来看一个简单的例子,使用 for-await-of 循环遍历一个异步迭代器:
const asyncIterable = { [Symbol.asyncIterator]() { return { i: 0, next() { if (this.i < 3) { return Promise.resolve({ value: this.i++, done: false }); } return Promise.resolve({ done: true }); } }; } }; (async function() { for await (let num of asyncIterable) { console.log(num); } })();
上面的代码中,我们定义了一个异步迭代器 asyncIterable,它返回每次迭代时的 promise 对象。在循环体内部,我们将异步操作的结果保存在变量 num 中,然后打印出来。
for-await-of 的指导意义
使用 for-await-of 循环,相比于传统的回调函数方式,能够更方便的展开嵌套的异步操作,使得代码的可读性和可维护性更强。
举个例子,我们来模拟一个对学生列表进行批量处理的场景,首先需要获取学生列表,然后依次处理每个学生的信息。使用传统的回调函数方式,代码如下:
function handleStudents() { getStudents((err, students) => { if (err) { console.error(err); return; } for (let i = 0; i < students.length; i++) { handleStudent(students[i], (err, result) => { if (err) { console.error(err); } else { console.log(result); } }); } }); } function getStudents(callback) { setTimeout(() => { callback(null, [ { id: 1, name: 'Tom' }, { id: 2, name: 'Jerry' }, { id: 3, name: 'Linda' } ]); }, 1000); } function handleStudent(student, callback) { setTimeout(() => { console.log(`Handling student ${student.name}...`); callback(null, 'Done'); }, 1000); } handleStudents();
可以看到,代码中存在多层嵌套函数和回调函数,不仅使用起来比较麻烦,而且容易出现回调地狱的问题。使用 for-await-of 循环改写后的代码如下:
async function handleStudents() { const students = await getStudents(); for await (const student of students) { const result = await handleStudent(student); console.log(result); } } function getStudents() { return new Promise(resolve => { setTimeout(() => { resolve([ { id: 1, name: 'Tom' }, { id: 2, name: 'Jerry' }, { id: 3, name: 'Linda' } ]); }, 1000); }); } function handleStudent(student) { return new Promise(resolve => { setTimeout(() => { console.log(`Handling student ${student.name}...`); resolve('Done'); }, 1000); }); } handleStudents();
可以看到,代码中不存在多层嵌套函数和回调函数,使用起来更加简单,可读性和可维护性也更强。
总结
通过本文的介绍,我们了解了 ES8 中引入的 for-await-of 循环,它是处理异步操作的利器,能够更方便的展开嵌套的异步操作,避免了回调地狱的问题。在实际开发中,我们可以使用 for-await-of 循环,让异步编程变得更加易读、易维护。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65b1a155add4f0e0ffad6974