讲解 ES8 中的 for-await-of 循环,解决异步编程中的痛点

在异步编程中,面对多个异步操作的情况,往往需要用到循环来处理每个异步操作的结果。而 ES8 中引入了一个新的循环结构 for-await-of,可以更方便的处理异步操作的结果,避免了回调地狱的问题。

for-await-of 的用法

for-await-of 语句可以用于遍历异步操作返回的迭代器(Iterator),语法如下:

其中,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