Но я все еще не на 100% уверен, что обещание останется в ожидании навсегда.
Я согласен, что это не очень хорошая идея. Лучшим подходом было бы поместить всю цепочку обещаний в обсуждаемую функцию.
Другим вариантом будет возвращение кэшированного значения, когда отклоненный вызов не инициирует новый запрос. Это решит вашу проблему: вам всегда нужно возвращать обещание:
function debounce(func, wait) {
var timeout, value;
return function() {
if (!timeout) value = func.apply(this, arguments);
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = value = null;
}, wait);
return value;
};
}
Конечно, это будет означать, что в некоторых случаях будет вызываться несколько обработчиков then
, когда ваш запрос завершится. Это зависит от вашего приложения, является ли это проблемой или просто лишней работой.
Другой вопрос заключается в том, что шаблоны Promise Anti предлагали не создавать ненужных обещаний. Но в моем случае создание нового обещания кажется необходимым.
Необходимо только одно обещание: когда вы создаете никогда не выполненное. Вы можете написать это как
function debounce(func, wait) {
var timeout;
const never = new Promise(resolve => {/* do nothing*/});
return function() {
const result = timeout ? never : func.apply(this, arguments);
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
}, wait);
return result;
};
}
Или, по крайней мере, избегать части .then(resolve).catch(reject)
. Лучше пиши
function debounce(func, wait) {
var timeout;
return function() {
return new Promise(resolve => {
if (!timeout) resolve(func.apply(this, arguments));
// ^^^^^^^
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
}, wait);
});
};
}
И если вы решите отклонить обещание в случае, если тайм-аут еще не наступил (чтобы вызывающий код мог обработать отклонение), вам также не нужно new Promise
:
function debounce(func, wait) {
var timeout;
return function() {
const result = timeout
? Promise.reject(new Error("called during debounce period"))
: Promise.resolve(func.apply(this, arguments));
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
}, wait);
return result;
};
}