Выполнение асинхронных функций в последовательности


Я реализовал функцию для практики, который принимает коллекцию асинхронные функции и функции обратного вызова. Он выполняет функции в последовательности затем вызывает обратный вызов с результатами (исходя из вызовов асинхронных функций). Это частично имитирует поведение ряда функций в асинхронных библиотека

Функция

const series = (tasks, cb) => {
    let results = [];
    const iterator = index => {
        if (index === tasks.length) {
            return;
        }
        const task = tasks[index];
        task(val => {
            results.push(val);
            iterator(index + 1);
            if (index === tasks.length - 1) {
                cb(results);
            }
        });
    }
    iterator(0);
}

Использование

const tasks = [
    cb => {
        setTimeout(() => {
            cb('done 1');
        }, 1000);
    },
    cb => {
        setTimeout(() => {
            cb('done 2');
        }, 1000);
    },
    cb => {
        setTimeout(() => {
            cb('done 3');
        }, 1000);
    }
];

series(tasks, results => {
    console.log(results);
});

// outputs ['done 1', 'done 2', 'done 3'] after 3 seconds

Что вы думаете о моем подходе? Как бы вы это реализовать? Используя обычный JavaScript.



109
1
задан 21 марта 2018 в 07:03 Источник Поделиться
Комментарии
1 ответ

Краткий обзор.

Он не пуленепробиваемый. Настолько, что это ошибка, одетый в JavaScript.

Вы должны защитить их от неправильного использования, случайной ошибки или невыполнение.

Следующий фрагмент кода показывает различные способы его не удастся.

series([cb => {
if (Math.random() < 0.01) { throw "Spanner" }
const handle = setTimeout(() => {
cb('done');
console.log("Not really done");
cb('Done again');
}, 1000);
// Indeterminate completing clause
setTimeout(() => clearTimeout(handle), Math.random() * 2000);
}, "Iron filings"], undefined); // undefined for a free throw if it got to the end

Почему бы не использовать обещания и асинхронных функций???

Следующие иммунитет к любой из вышеперечисленных spannering.

async function series(tasks, tasksComplete) {
if (Array.isArray(tasks)) {
const timeoutPeriod = 5000; // 5 seconds and your out. Task can still complete
const results = [];
while (tasks.length) {
const task = tasks.shift();
if (typeof task === "function") {
await new Promise(done => {
setTimeout(() => done("Too slow!") , timeoutPeriod);
task(done);
})
.then(result => results.push(result))
.catch(error => results.push(error)) // assuming good to continue
}
}
if (typeof taskComplete === "function") { tasksComplete(results) }
}
}

Обновление

Вместо ответа и комментария вы сделали следующие могут удовлетворить ваши потребности лучше.

А не пройти обратный вызов функции, то функция возвращает обещание, которое будет решать, когда все задание успешно завершено, если есть проблема по пути функция прекращается, при этом возвращая код ошибки.

Также стек результаты передаются к каждой задаче. А не последние результаты весь стек результаты прошли. Это задача, какие результаты он должен использовать.

Также добавлено несколько вариантов. Остановка на ошибку, если верно остановится на первой ошибке, и время ожидания больше 0, то будет ошибка времени ожидания на задачи.

// Returns promise to do tasks in series
// stopOnError is false then continues tasks if there is an error placing
// the error on the results stack
// timeout if > 0 will throw error if task takes too long.
// Promise resolves with the results stack for both completed and error
function series(tasks, stopOnError = true, timeout = 0) {
const results = [];
async function doEachTask(completed, failed) {
while (tasks.length) {
const task = tasks.shift();
if (typeof task === "function") {
await new Promise((done,error) => {
if (timeout) {
setTimeout(()=> error(new Error("Too slow!")) , timeout);
}
task(done, results);
})
.then(result => results.push(result))
.catch(error => {
results.push(error);
if (stopOnError) { failed(results) }
});

}
}
completed(results);
}
return new Promise(doEachTask);
}

Использовать следующим образом

series([
(complete, data) => {
setTimeout(()=> {
complete("Task1 complete");
},1000)
},
(complete, data) => {
console.log("Task 2 has data : "+data[0]);
setTimeout(()=> {
complete("Task2 complete");
},1000)
}])
.then(results => console.log(results))
.catch(results => console.log("Error and available results : " + results));

2
ответ дан 21 марта 2018 в 08:03 Источник Поделиться