Вопрос сложно описать, поэтому позвольте мне опубликовать пример.
Контекст - AngularJS $q, но также приветствуются любые решения, основанные на ES6 Promise.
Предположим, мы хотим отменить запрос $http. В AngularJS это реализовано путем предоставления метода обещания A для $http.get(). Выполнить обещание A приведет к отмене запроса. Итак, код будет выглядеть так:
function httpCall() {
const promiseA = $q.defer();
const promiseB = $http.get(url, { timeout: promiseA.promise });
return promiseB;
}
Чтобы вернуть promiseA, чтобы вызывающий httpCall мог отменить запрос, я нашел единственный способ назначить его promiseB, например:
function httpCall() {
const promiseA = $q.defer();
let promiseB = $http.get(url, { timeout: promiseA });
promiseB.canceller = promiseA;
return promiseB;
}
Проблема в том, что promiseB может передаваться через длинную цепочку обещаний (такую как отправка действий, отображение и другие пост-процессы), например:
function doSomeAction() {
return httpCall()
.then((response) => {
processResponse(response);
return response;
});
}
Очевидно, что возвращаемое значение doSomeAction НЕ совпадает с обещанием источника promiseB.
Таким образом, если у меня есть функция, которая вызывает doSomeAction(), эта функция не сможет получить promiseB (она может получить только обещание возврата doSomeAction()) и, следовательно, не сможет отменить запрос.
Кто-то может сказать, что мы можем передавать данные (promiseA) по цепочке. Однако я считаю, что существование promiseA должно быть прозрачным для самой цепочки, то есть функции в цепочке никогда не должны знать о существовании promiseA. Таким образом, я не могу зависеть от цепочки в передаче данных за меня.
Любые предложения приветствуются.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Незнание о promiseA имеет смысл, поскольку все происходит на разных уровнях абстракции. doSomeAction абстрагирует HTTP-вызов и предоставляет любой API, который отменяет базовый HTTP-вызов, прерывает абстракцию и раскрывает детали реализации doSomeAction. Вместо этого я бы подумал о том, чтобы сделать doSomeAction отменяемым, то есть предоставить метод cancel для объекта, который он возвращает. Этот метод отмены может отменить базовый HTTP-запрос (или несколько из них, если их несколько) или пропустить отмену, если HTTP-запрос не был сделан, а данные были взяты из локального хранилища, или делать все, что имеет смысл для doSomeAction, а не только конкретный HTTP-запрос, который просто часть общей картины на этом слое.
Это имеет смысл, если учесть, что цепочка может быть сложной (например, $q.all()). Пока я все еще пытаюсь выяснить, как сделать его универсальным, я выберу это как последнее решение. Спасибо @nutic
Свойство
timeoutконфигурации $ http должно быть обещанием. ПеременнаяpromiseAне является объектом обещания; это отложенный. Объект обещания -$q.deferred().promise.