MST

星途 面试题库

面试题:JavaScript生成器在异步操作中的应用

假设你有一个需要按顺序执行多个异步任务的场景(例如依次读取多个文件内容),如何使用JavaScript的生成器和yield关键字来简化这种异步操作的控制流程?请给出具体代码实现,并解释其原理。
24.9万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

代码实现

function readFileAsync(filePath) {
    return new Promise((resolve, reject) => {
        // 模拟异步读取文件操作
        setTimeout(() => {
            resolve(`File content of ${filePath}`);
        }, 1000);
    });
}

function* asyncTasks() {
    const file1Content = yield readFileAsync('file1.txt');
    console.log(file1Content);
    const file2Content = yield readFileAsync('file2.txt');
    console.log(file2Content);
    const file3Content = yield readFileAsync('file3.txt');
    console.log(file3Content);
}

const taskGenerator = asyncTasks();
let task = taskGenerator.next();

while (!task.done) {
    task.value.then(result => {
        task = taskGenerator.next(result);
    }).catch(error => {
        console.error(error);
        task = taskGenerator.throw(error);
    });
}

原理解释

  1. 生成器(Generator):生成器是一种特殊的函数,它可以暂停和恢复执行。通过function*关键字定义,使用yield关键字暂停函数执行并返回一个值。当生成器函数被调用时,它不会立即执行,而是返回一个生成器对象。
  2. yield关键字:在生成器函数内部,yield用于暂停函数的执行,并返回其后跟随的表达式的值。它可以看作是一个“返回点”,下次调用next()方法时,生成器会从暂停的yield处继续执行。
  3. 异步任务控制:在上述代码中,asyncTasks是一个生成器函数,它包含多个异步任务(通过readFileAsync模拟)。每个yield后面跟一个Promise对象(代表异步操作)。生成器开始执行时,遇到第一个yield暂停,返回readFileAsync('file1.txt')这个Promise对象。
  4. 执行流程
    • 首先创建生成器对象taskGenerator并调用next()方法启动生成器,此时它暂停在第一个yield处,返回第一个异步任务(Promise)。
    • 使用.then()处理Promise的解析结果,当Promise被解析(即文件读取完成),将结果作为参数传递给next()方法,生成器从暂停处继续执行,将解析结果赋值给file1Content,并打印内容。然后遇到下一个yield再次暂停,返回第二个异步任务。
    • 重复上述过程,直到所有异步任务完成,生成器的done属性变为true,循环结束。
  5. 异常处理:如果Promise被拒绝(即异步操作出错),通过.catch()捕获错误,并使用throw(error)将错误传递给生成器,生成器会在暂停处抛出该错误,可以在生成器内部进行相应处理。