Я последнее время давно не вывожу статью, причина очень проста, я был очень занят в последнее время,
Честно говоря, в последнее время я был очень растерян. О технике, о жизни. Я также нашел много друзей на большой фабрике, чтобы поболтать, желая поделиться некоторыми идеями для дальнейшего развития. В нем также говорилось о собеседовании и о некоторых вопросах, которые будут заданы кандидату при приеме на работу. Просто у меня давно не было интервью, поэтому я выбрал несколько. В последнее время будет серия разборов некоторых вопросов интервью.
Сегодня это бит бит:
实现一个批量请求函数 multiRequest(urls, maxNum),要求如下:
• 要求最大并发数 maxNum
• 每当有一个请求返回,就留下一个空位,可以增加新的请求
• 所有请求完成后,结果按照 urls 里面的顺序依次打出
Я думаю, что многие студенты более или менее видели эту тему.Далее я постараюсь дать полный разбор этой темы шаг за шагом от места, разбора проблемы до финальной реализации.
Сцены
Предположим, есть такой сценарий: нужно отправить 30 асинхронных запросов, но по какой-то причине мы должны контролировать количество одновременных запросов в пределах 5, при этом также максимально быстро получить результаты ответа.
То, что должно быть сделано?
Сначала давайте разберемсяAjax
последовательный и параллельный.
Последовательная и параллельная реализация Ajax на основе Promise.all
Мы всегда основываемся наpromise
Чтобы инкапсулировать асинхронные запросы, это в основном для асинхронных запросов.
- Последовательный: после завершения асинхронного запроса выполняется следующий запрос.
- Параллельный: несколько асинхронных запросов выполняются одновременно.
путем определения некоторыхpromise实例
для подробной демонстрации последовательного/параллельного режима.
сериал
var p = function () {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('1000')
resolve()
}, 1000)
})
}
var p1 = function () {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('2000')
resolve()
}, 2000)
})
}
var p2 = function () {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('3000')
resolve()
}, 3000)
})
}
p().then(() => {
return p1()
}).then(() => {
return p2()
}).then(() => {
console.log('end')
})
Например, последовательный интерфейс будет выполнять соответствующие запросы интерфейса последовательно сверху вниз.
параллельно
Обычно, когда нам нужно убедиться, что код выполняется после многократной асинхронной обработки, мы будем использовать:
Promise.all(promises: []).then(fun: function);
Promise.all
может гарантировать,promises
все в массивеpromise
объекты достигаютresolve
статус, выполнитьthen
Перезвоните.
var promises = function () {
return [1000, 2000, 3000].map(current => {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log(current)
}, current)
})
})
}
Promise.all(promises()).then(() => {
console.log('end')
})
Предел параллелизма Promise.all
Рассмотрим сценарий в это время: если вашpromises
Каждый объект массиваhttp请求
, и таких объектов сотни тысяч.
Тогда произойдет то, что вы отправите сотни тысяч в одно мгновениеhttp请求
, что может привести к накоплению большого количества стеков вызовов и вызвать переполнение памяти.
На этом этапе нам необходимо рассмотретьPromise.all
Сделайте ограничение параллелизма.
Promise.all并发限制
Относится к параллельному выполнению в каждый моментpromise
Количество фиксировано, а окончательный результат выполнения остается таким же, как и исходныйPromise.all
Последовательный.
Реализация темы
Анализ мыслей
Все реализовано с помощью рекурсивных вызовов: количество запросов, отправленных изначально, ограничено максимально допустимым, и каждый из этих запросов должен продолжать отправляться рекурсивно после завершения, что определяется переданным индексом.urls
В частности, чтоURL
, чтобы гарантировать, что порядок конечного вывода не будет хаотичным, а будет выводиться последовательно.
Код
function multiRequest(urls = [], maxNum) {
// 请求总数量
const len = urls.length;
// 根据请求数量创建一个数组来保存请求的结果
const result = new Array(len).fill(false);
// 当前完成的数量
let count = 0;
return new Promise((resolve, reject) => {
// 请求maxNum个
while (count < maxNum) {
next();
}
function next() {
let current = count++;
// 处理边界条件
if (current >= len) {
// 请求全部完成就将promise置为成功状态, 然后将result作为promise值返回
!result.includes(false) && resolve(result);
return;
}
const url = urls[current];
console.log(`开始 ${current}`, new Date().toLocaleString());
fetch(url)
.then((res) => {
// 保存请求结果
result[current] = res;
console.log(`完成 ${current}`, new Date().toLocaleString());
// 请求没有全部完成, 就递归
if (current < len) {
next();
}
})
.catch((err) => {
console.log(`结束 ${current}`, new Date().toLocaleString());
result[current] = err;
// 请求没有全部完成, 就递归
if (current < len) {
next();
}
});
}
});
}