티스토리 뷰

반응형

자바스크립트에서 ajax에서 그 결과를 받은 후 다시 ajax를 반복해서 실행하는 방법이 있는가?

예를들어, 폴더의 파일에 대한 처리를 해당 폴더의 자료의 개수가 몇만개가 있다면 이것이 끝나고 처리하고 결과를 받은 후 처리하고 이렇게 프로그램을 만든다면 어떻게 해야 할까요?

 

 

자바스크립트에서 AJAX 요청을 반복적으로 실행하며 이전 요청의 결과를 기반으로 작업을 진행하는 방식은 비동기적으로 수행됩니다. 이를 구현하려면 다음과 같은 방식을 사용할 수 있습니다:

  1. 재귀적 AJAX 호출: 하나의 요청이 완료된 후 조건에 따라 다음 요청을 실행하는 방법입니다.
  2. Promise 또는 async/await 사용: 비동기 처리를 체계적으로 작성할 수 있도록 돕습니다.

예제: 재귀적 AJAX 호출

function processFiles(folderId, startIndex = 0) {
    $.ajax({
        url: 'process_files.php',
        method: 'POST',
        data: { folderId: folderId, startIndex: startIndex },
        success: function(response) {
            console.log('Processed batch:', response);

            if (response.hasMoreFiles) {
                // 다음 배치를 처리
                processFiles(folderId, response.nextIndex);
            } else {
                console.log('모든 파일 처리가 완료되었습니다.');
            }
        },
        error: function(error) {
            console.error('오류 발생:', error);
        }
    });
}

// 실행
processFiles('myFolderId');
  • 설명:
    • startIndex는 현재 처리 중인 파일의 시작 인덱스를 나타냅니다.
    • 서버는 hasMoreFiles 플래그와 nextIndex 값을 반환하여 다음 요청을 알립니다.

예제: async/await를 사용한 반복 요청

async function processFiles(folderId, startIndex = 0) {
    try {
        const response = await $.ajax({
            url: 'process_files.php',
            method: 'POST',
            data: { folderId: folderId, startIndex: startIndex }
        });

        console.log('Processed batch:', response);

        if (response.hasMoreFiles) {
            // 다음 배치를 처리
            await processFiles(folderId, response.nextIndex);
        } else {
            console.log('모든 파일 처리가 완료되었습니다.');
        }
    } catch (error) {
        console.error('오류 발생:', error);
    }
}

// 실행
processFiles('myFolderId');

서버 측 응답 예시 (PHP)

<?php
// 서버는 현재 요청에 대한 배치 데이터를 처리하고 반환
$folderId = $_POST['folderId'];
$startIndex = $_POST['startIndex'];

// 처리할 파일 목록을 얻음 (데모 데이터를 사용)
$files = array_slice(scandir("/path/to/$folderId"), $startIndex, 100); // 100개씩 처리
$hasMoreFiles = count(scandir("/path/to/$folderId")) > $startIndex + 100;

// 파일 처리 로직 추가 (예: 데이터베이스에 기록 또는 파일 이동)
foreach ($files as $file) {
    // 파일 처리
}

// 결과 반환
echo json_encode([
    'hasMoreFiles' => $hasMoreFiles,
    'nextIndex' => $startIndex + 100,
    'processedFiles' => $files
]);

주의 사항

  1. 대량 데이터 처리 최적화:
    • 각 AJAX 호출은 특정 배치 크기(예: 100개)로 제한합니다.
    • 서버 부하를 고려하여 처리량을 조절하세요.
  2. 오류 처리:
    • 실패 시 재시도 로직을 추가하거나 중단할 조건을 설정하세요.
  3. 네트워크 상태:
    • 네트워크 연결 불안정 시 요청이 중단되지 않도록 대기 시간을 설정하거나 타임아웃을 관리하세요.
  4. 비동기 작업 완료 여부:
    • 모든 작업이 끝난 후 UI 업데이트나 사용자 알림을 추가하세요.

위 코드를 기반으로 폴더의 대량 파일 처리를 AJAX로 반복 실행할 수 있습니다. 필요하면 로직을 추가적으로 커스터마이징하세요.

 

async/await를 사용한 반복 요청 이 기법으로 계속 무한 반복은 아니지만 결과를 받은 후 실행하는 것이 가능한 것인가?

 

네, async/await를 사용하면 결과를 받은 후에만 다음 요청을 실행하도록 구현할 수 있습니다. 이를 통해 비동기 요청을 직렬적으로 처리할 수 있고, 특정 조건에 따라 반복을 중단할 수도 있습니다. 무한 반복이 아니더라도 특정 조건을 만족할 때까지 요청을 반복하거나 중단하는 것이 가능합니다.

아래는 이를 명확히 설명하는 예제입니다.


async/await로 조건부 반복 AJAX 요청

async function processFiles(folderId) {
    let hasMoreFiles = true; // 조건부 반복을 위한 플래그
    let startIndex = 0; // 초기값 설정

    while (hasMoreFiles) { // 조건이 true일 동안 반복 실행
        try {
            const response = await $.ajax({
                url: 'process_files.php', // 서버 URL
                method: 'POST',
                data: { folderId: folderId, startIndex: startIndex }
            });

            console.log('Processed batch:', response);

            // 서버에서 다음 요청 여부와 인덱스 정보 전달
            hasMoreFiles = response.hasMoreFiles;
            startIndex = response.nextIndex;

            // 결과에 따라 조건을 업데이트
            if (!hasMoreFiles) {
                console.log('모든 파일 처리가 완료되었습니다.');
            }
        } catch (error) {
            console.error('오류 발생:', error);
            break; // 오류 시 반복 중단
        }
    }
}

// 실행
processFiles('myFolderId');

작동 방식

  1. while 루프를 사용하여 반복 요청:
    • hasMoreFiles 플래그가 true일 때만 반복 실행.
    • 서버 응답(response)에 따라 hasMoreFiles와 startIndex를 업데이트.
  2. await로 순차 실행:
    • AJAX 요청이 완료될 때까지 기다린 후 다음 작업을 실행.
    • 결과를 기다린 후 로직을 수행하므로 이전 요청이 완료된 뒤에만 다음 요청이 실행.
  3. 반복 중단 조건:
    • 서버에서 hasMoreFiles가 false로 반환되면 루프가 종료됩니다.
    • 오류가 발생하면 catch 블록에서 반복을 중단할 수 있습니다.

PHP 서버 예시

<?php
$folderId = $_POST['folderId'];
$startIndex = $_POST['startIndex'];

// 폴더 내 파일 목록을 가져옵니다
$files = array_slice(scandir("/path/to/$folderId"), $startIndex, 100); // 100개씩 처리
$totalFiles = count(scandir("/path/to/$folderId"));
$hasMoreFiles = $startIndex + 100 < $totalFiles;

// 파일 처리 로직 (여기에 원하는 작업 추가)
foreach ($files as $file) {
    // 예: 파일 이동 또는 데이터베이스 저장
}

// 결과 반환
echo json_encode([
    'hasMoreFiles' => $hasMoreFiles,
    'nextIndex' => $startIndex + 100,
    'processedFiles' => $files
]);

장점

  • 요청 결과를 기다린 후에만 다음 작업을 실행하기 때문에 제어가 용이합니다.
  • 비동기 작업을 체계적으로 관리할 수 있어 가독성이 높아집니다.
  • 서버 부하를 줄이기 위해 배치 크기와 요청 간격을 조정할 수 있습니다.

추가 조건이 필요한 경우

  • 요청 간 딜레이: 서버에 과부하를 줄이기 위해 요청 간에 딜레이를 추가.
    await new Promise(resolve => setTimeout(resolve, 1000)); // 1초 대기
    
  • 요청 최대 횟수 제한:
    let maxRequests = 10;
    while (hasMoreFiles && maxRequests-- > 0) {
        // 요청 로직
    }
    

이 구조를 활용하면 결과를 받은 후 조건에 따라 다음 요청을 실행하는 방식으로 유연하게 제어할 수 있습니다.

 

Promise와 async/await의 선택 기준 ?

 

Promise와 async/await는 모두 비동기 코드를 처리하는 JavaScript의 기능입니다. async/await는 Promise의 문법적 설탕(syntactic sugar)으로, Promise 기반의 비동기 처리를 보다 직관적이고 동기 코드처럼 작성할 수 있게 도와줍니다.


1. Promise와 async/await의 기본 차이점

특성 Promise async/await

사용 방식 .then()과 .catch() 체인을 통해 처리. await 키워드를 사용하여 비동기 작업이 완료될 때까지 기다림.
코드 가독성 복잡한 비동기 처리에서 가독성이 낮아질 수 있음 (콜백 체인 가능성). 동기 코드처럼 작성할 수 있어 가독성이 더 좋음.
에러 처리 .catch() 또는 .then() 내부의 에러 핸들러 사용. try...catch 블록으로 명확하게 에러 처리 가능.
동기화처럼 보이는가 비동기적으로 동작이 명확함. 동기 코드처럼 보여 직관적임.

2. Promise

Promise 기본 사용법

Promise는 비동기 작업의 성공(resolve)과 실패(reject) 상태를 처리하는 객체입니다.

function getData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = true; // 조건에 따라 성공/실패
            if (success) {
                resolve('데이터 성공적으로 가져옴');
            } else {
                reject('데이터 가져오기 실패');
            }
        }, 1000);
    });
}

getData()
    .then(result => {
        console.log(result); // 성공 시 실행
    })
    .catch(error => {
        console.error(error); // 실패 시 실행
    });

특징

  1. .then()과 .catch() 체인을 사용하여 비동기 작업 완료 후 동작을 지정.
  2. 비동기 작업이 계속될수록 .then() 체인이 길어질 가능성이 있음.
  3. 중첩된 비동기 호출 시 **"Promise hell"**로 가독성이 떨어질 수 있음.

3. async/await

async/await 기본 사용법

async/await는 Promise를 더 간단하고 동기 코드처럼 작성할 수 있게 합니다.

async function getData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = true;
            if (success) {
                resolve('데이터 성공적으로 가져옴');
            } else {
                reject('데이터 가져오기 실패');
            }
        }, 1000);
    });
}

async function processData() {
    try {
        const result = await getData(); // 비동기 작업 완료를 기다림
        console.log(result); // 성공 시 실행
    } catch (error) {
        console.error(error); // 실패 시 실행
    }
}

processData();

특징

  1. await는 Promise가 처리될 때까지 기다린 후 값을 반환.
  2. 동기 코드처럼 작동해 가독성과 유지보수성이 향상됨.
  3. try...catch로 명확하게 에러를 처리.

4. Promise와 async/await의 주요 차이점

특성 Promise async/await

구조 체인을 사용해 .then()으로 결과를 처리. 비동기 작업을 await로 대기, 결과를 변수에 직접 할당 가능.
가독성 긴 체인과 중첩된 호출은 가독성이 떨어짐. 동기 코드처럼 작성 가능해 가독성이 뛰어남.
에러 처리 .catch()를 추가하거나 .then() 내에서 에러 핸들링. try...catch로 명확하게 에러 처리 가능.
병렬 작업 처리 Promise.all() 또는 Promise.race()로 병렬 작업 가능. await Promise.all()로 동일하게 병렬 작업 가능.
사용 시기 간단한 작업에 적합하며 라이브러리에서 많이 사용됨. 복잡한 비동기 로직에서 더 적합, 가독성과 유지보수성이 중요할 때 사용.

5. Promise와 async/await 비교 예시

Promise로 복잡한 비동기 작업

function fetchData() {
    return new Promise(resolve => setTimeout(() => resolve('Data 1'), 1000));
}

function processData(data) {
    return new Promise(resolve => setTimeout(() => resolve(`${data} -> Processed`), 1000));
}

function saveData(data) {
    return new Promise(resolve => setTimeout(() => resolve(`${data} -> Saved`), 1000));
}

fetchData()
    .then(data => {
        console.log(data);
        return processData(data);
    })
    .then(processedData => {
        console.log(processedData);
        return saveData(processedData);
    })
    .then(savedData => {
        console.log(savedData);
    })
    .catch(error => {
        console.error('오류 발생:', error);
    });

async/await로 복잡한 비동기 작업

async function handleData() {
    try {
        const data = await fetchData();
        console.log(data);

        const processedData = await processData(data);
        console.log(processedData);

        const savedData = await saveData(processedData);
        console.log(savedData);
    } catch (error) {
        console.error('오류 발생:', error);
    }
}

handleData();

Promise와 async/await의 선택 기준

  • Promise를 사용할 때:
    • 간단한 비동기 작업.
    • 라이브러리나 기존 코드베이스에서 Promise를 주로 사용하는 경우.
  • async/await을 사용할 때:
    • 비동기 작업의 순서를 명확히 표현해야 할 때.
    • 에러 처리가 중요한 경우.
    • 비동기 로직이 복잡하고 긴 체인을 피하고 싶을 때.

async/await은 대규모 프로젝트나 복잡한 비동기 로직에서 특히 더 효율적입니다. Promise는 간단한 작업이나 콜백 기반 코드와의 호환성에서 유리합니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함