MST

星途 面试题库

面试题:JavaScript高级生成器嵌套调用与异步控制流

结合生成器嵌套调用和异步操作(如`fetch`进行网络请求),实现一个复杂的异步控制流。假设有一系列相互依赖的网络请求,`req1`的结果作为`req2`的参数,`req2`的结果作为`req3`的参数,且每个请求都可能失败。要求使用生成器嵌套调用的方式进行管理,确保每个请求失败时能够进行适当的重试机制,同时保证代码的可读性和可维护性。请给出详细的代码实现及思路。
22.5万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

思路

  1. 生成器函数:定义多个生成器函数,每个函数负责处理一个网络请求及其重试逻辑。
  2. 嵌套调用:通过在生成器函数内部yield另一个生成器函数来实现嵌套调用,确保请求之间的依赖关系。
  3. 异步操作:使用fetch进行网络请求,将其包装成返回Promise的函数以便在生成器中使用。
  4. 重试机制:在每个生成器函数中实现重试逻辑,如果请求失败则按照设定的次数进行重试。

代码实现

function fetchWithRetry(url, options = {}, maxRetries = 3, retryDelay = 1000) {
    let retries = 0;
    return new Promise((resolve, reject) => {
        function attempt() {
            fetch(url, options)
              .then(response => {
                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status}`);
                    }
                    resolve(response);
                })
              .catch(error => {
                    retries++;
                    if (retries <= maxRetries) {
                        setTimeout(attempt, retryDelay * retries);
                    } else {
                        reject(error);
                    }
                });
        }
        attempt();
    });
}

function* req1() {
    try {
        const response = yield fetchWithRetry('url1');
        return response.json();
    } catch (error) {
        console.error('req1 failed:', error);
        throw error;
    }
}

function* req2(dataFromReq1) {
    try {
        const response = yield fetchWithRetry('url2', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(dataFromReq1)
        });
        return response.json();
    } catch (error) {
        console.error('req2 failed:', error);
        throw error;
    }
}

function* req3(dataFromReq2) {
    try {
        const response = yield fetchWithRetry('url3', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(dataFromReq2)
        });
        return response.json();
    } catch (error) {
        console.error('req3 failed:', error);
        throw error;
    }
}

function runGenerator(generator) {
    const gen = generator();
    function handleResult(result) {
        if (result.done) {
            return result.value;
        }
        return Promise.resolve(result.value)
          .then(data => handleResult(gen.next(data)))
          .catch(error => handleResult(gen.throw(error)));
    }
    return handleResult(gen.next());
}

runGenerator(function* () {
    const data1 = yield* req1();
    const data2 = yield* req2(data1);
    const data3 = yield* req3(data2);
    console.log('Final result:', data3);
})
 .catch(error => console.error('Overall process failed:', error));

解释

  1. fetchWithRetry函数:封装了fetch请求,并添加了重试逻辑。它接受URL、请求选项、最大重试次数和重试延迟作为参数。
  2. req1req2req3生成器函数:每个函数负责处理一个网络请求,使用yield暂停执行并等待fetchWithRetry返回结果。如果请求失败,会捕获错误并重新抛出。
  3. runGenerator函数:用于运行生成器,处理生成器的nextthrow操作,通过递归调用handleResult来处理生成器的嵌套调用。
  4. 最后部分:通过runGenerator运行一个主生成器,该生成器按顺序调用req1req2req3,并处理最终结果或错误。