Показать сообщение отдельно
  #6 (permalink)  
Старый 04.10.2017, 13:08
Аватар для Alexandroppolus
Профессор
Отправить личное сообщение для Alexandroppolus Посмотреть профиль Найти все сообщения от Alexandroppolus
 
Регистрация: 25.10.2016
Сообщений: 1,012

Навскидку видится такой вариант (сотворено на коленке, не дебажил):

function request(key, param, callback) { ... } // делает запрос в API

function APIClient(key, data) {
	this._key = key;
	this._data = data;
	this.nextTime = 0;
	this.loading = false;
	this._finish = this._finish.bind(this);
}

APIClient.prototype.start = function() {
	if (this._data.params.length) {
		var param = this._data.params.pop();
		request(this._key, param, this._finish);
		this._data.requests++;
		this.loading = true;
		this.param = param;
		this.nextTime = Date.now() + 1000; // следующий запрос через секунду, не ранее
	}
};
APIClient.prototype._finish = function(error) {
	if (error) {
		// запрос был с ошибкой, будем пробовать ещё раз для этого параметра
		this._data.params.push(this.param);
	}
	this.loading = false;
	this.param = null;
	this._data.requests--;
	if (!this._data.requests && !this._data.params.length && this._data.timer) {
		clearInterval(this._data.timer);
		this._data.timer = null;
		this._data.callback();
	}
};

function loadAll(keys, limit, params, callback) {
	var data = {
		params: params,
		requests: 0,
		timer: null,
		callback: callback
	};
	var clients = [];
	for (var i = 0; i < keys.length; ++i) {
		for (var j = 0; j < limit; ++j) {
			clients.push(new APIClient(keys[i], data));
		}
	}
	data.timer = setInterval(function () {
		var time = Date.now();
		for (var i = 0; i < clients.length; ++i) {
			var client = clients[i];
			if (time >= client.nextTime && !client.loading) {
				client.start();
			}
		}
	}, 300);
}

// запуск
loadAll([...], 8, [...], function() {
    ...
});


для каждого ключа создаем по 8 клиентов, все складываем в массив. Каждый клиент делает запрос не чаще раза в секунду. Отмечает время старта запроса (точнее, время следующего старта). И есть один общий таймер, который проверяет всех клиентов и стартует тех, которые уже успели "отдохнуть". Последний клиент, завершившись, уничтожает таймер и вызывает общий колбэк.

при такой схеме никто никого не ждет.

если требуется минутный интервал между финишем предыдущего запроса и стартом нового, то установку nextTime перенеси в _finish

Последний раз редактировалось Alexandroppolus, 04.10.2017 в 13:32.
Ответить с цитированием