Обещание отклонить - время ожидания регистрации - PullRequest
1 голос
/ 20 марта 2019

У меня есть реализация обещанной гонки за тайм-аут.Я хочу записать ошибку тайм-аута в случае тайм-аута.

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

Где разместить errorLogger.info(message), чтобы он не выполнялся в случае non-timeout?Я думаю, что я неправильно это формулирую, поэтому он выводит данные до того, как он на самом деле отвергает.

return Promise.race([
   fetch(url, options)
  .then(function (response) {
    if (response.status >= 400) {
      const message = `fetch-utility.js: bad server response while fetching url=${url} with options=${options}.`;


      errorLogger.error(`${message} Response: status=${response.status} statusText:${response.statusText}.`);

      throw new BadServerResponseException(message, response.status);
    }
    return response;
  }),
  new Promise((_, reject) =>
    setTimeout(() => {
      const message = `fetch-utility.js: timeout happened while fetching details url=${url} with options=${options}. 
  The timeout set is ${timeout}.`;

      // TODO: this gets logged even the parallel wins - need to see better way to log this
      // errorLogger.error(message);

      reject(new TimeoutException(message));
    }, timeout),
  ),
]);

Ответы [ 3 ]

2 голосов
/ 20 марта 2019

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

Вместо этого вы можете связать then и catch в обещании, возвращенном Promise.race.Таким образом, вы должны сохранить аргументы race очень тонкими и переместить логику во внешнюю часть.

Что-то вроде:

return Promise.race([
    fetch(url, options),
    new Promise((_, reject) => setTimeout(() => reject("timeout"), timeout))
]).catch(function(error) {
    if (error === "timeout") {
        const message = "timeout happened";
        errorLogger.error(message);
        throw new TimeoutException(message);
    } else {
        const message = "fetch failed";
        errorLogger.error(message);
        throw new FetchException(message);
    }
}).then(function (response) {
    if (response.status >= 400) {
        const message = "bad response";
        errorLogger.error(message);
        throw new BadServerResponseException(message, response.status);
    }
    return response; // Success within timeout!
});
2 голосов
/ 20 марта 2019

Не стоит смешивать логику тайм-аута с вашей реальной бизнес-логикой. Вы должны абстрагировать логику тайм-аута, которая позволит вам сделать это:

function timeoutPromise(timeout) {
    return new Promise(res => setTimeout(res, timeout));
}

function withTimeout(timeout, promise, timeoutMessage) {
    let done = false;

    return Promise.race([
        Promise.resolve(promise)
            .finally(() => { done = true }),
        timeoutPromise(timeout)
            .then(() => {
                if (!done) {
                    const message = timeoutMessage || `Timeout after ${timeout} ms`;

                    errorLogger.error(message);

                    throw new TimeoutException(message);
                }
            })
   ]);
}

const timeout = 12345;

function performFetch(url, options) {
    return fetch(url, options)
        .then(function (response) {
            if (response.status >= 400) {
                const message = `fetch-utility.js: bad server response while fetching url=${url} with options=${options}.`;

                errorLogger.error(`${message} Response: status=${response.status} statusText:${response.statusText}.`);

                throw new BadServerResponseException(message, response.status);
            }

            return response;
        });
}

withTimeout(
    timeout, 
    performFetch(url, options),
   `fetch-utility.js: timeout happened while fetching details url=${url} with options=${options}. The timeout set is ${timeout}.`
)
0 голосов
/ 20 марта 2019

Я не уверен, что понимаю ваш вопрос на 100%, но если вы хотите «отменить» обещание, если для возврата чего-либо требуется слишком много времени, возможно, вы можете сделать что-то подобное

function myRequest() {
    return new Promise((resolve, reject) => {
        var mytimeout = setTimeout(function() {
            console.log('We are sorry but your request took too long');
            reject({
                err: "timed out"
            });
        }, 10)

        fetch('https://jsonplaceholder.typicode.com/todos/1')
        .then(response => response.json())
        .then(res => {
            resolve(res);
            clearTimeout(mytimeout)
        });
    });    
}

var promise = myRequest()
    .then(res => console.log(res))
    .catch(err => console.log(err))

Попробуйте изменить значение тайм-аута setTimeout, при достаточно малых значениях это вызовет исключение, а при относительно большом тайм-ауте обещание будет обработано данными

...