Настройка тайм-аута выборки и завершение запросов

JavaScript

1. Основное использование

Fetch — новый интерфейс для получения ресурсов в конце, который используется для замены громоздкого и громоздкого XMLHttpRequest, имеет концепцию объектов Request and Response и Headers, которая ближе к языку бэкенда, запрашивающему ресурсы.

  • простой GET-запрос

    fetch('https://www.baidu.com')
            .then(resp=>resp.text())  //  转换成文本对象
            .then(resp=>console.log(resp))  // 输出请求内容
            .catch(error => console.error(error));
    
  • простой POST-запрос

    fetch('https://www.easy-mock.com/mock/5ca59ba44ba86c23d507bd40/example/getUser',{method:"post"})
            .then(resp=>resp.json())  //转换成Json对象
            .then(resp=>console.log(resp)) //输出Json内容
            .catch(error => console.error(error));
    

    Дополнительные сведения о Fetch см. в документации MDN.developer.Mozilla.org/en-US/docs/…

2. Настройка времени ожидания

При использовании XMLHttpRequest можно установить время ожидания запроса, но после переключения на Fetch настройка времени ожидания пропадает.В случае ненадежной сети настройка времени ожидания часто очень полезна.

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

  1. Promise.race([promise1,promise2]) Передать несколько объектов Promise и дождаться завершения самого быстрого объекта.
  2. Promise.all([promise1,promise2]) Передать несколько объектов Promise и дождаться завершения всех объектов

С учетом вышеизложенного установка времени ожидания может быть достигнута путем объединения функции setTimeout

//ahutor:herbert qq:464884492
let timeoutPromise = (timeout) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("我是 timeoutPromise,已经完成了");
        }, timeout);
    });
}
let requestPromise = (url) => {
    return fetch(url);
};
Promise.race([timeoutPromise(1000), requestPromise("https://www.baidu.com")])
    .then(resp => {
        console.log(resp);
    })
    .catch(error => {
        console.log(error);
    });

3. Отменить запрос

Скопируйте приведенный выше код в консоль браузера и установите сеть Slow3G. Запустив его, мы обнаружим, что, хотя мы видим информацию о тайм-ауте в консоли, мы переключаемся на вкладку сети и обнаруживаем, что запрос все еще выполняется, и возвращается правильный контент. Это не тот результат, которого я хочу, я хочу, чтобы время ожидания истекло, и запрос должен быть завершен.

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

  timeoutResp=new Response("timeout", { status: 504, statusText: "timeout " })
  successResp=new Response("ok", { status: 200, statusText: "ok " })

AbortController используется для ручного завершения одного или нескольких запросов DOM, которые внедряются в запросы Fetch через AbortSignal объекта. Поэтому вам нужно идеально реализовать функцию тайм-аута и добавить это.

//ahutor:herbert qq:464884492
let controller = new AbortController();
let signal = controller.signal;

let timeoutPromise = (timeout) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(new Response("timeout", { status: 504, statusText: "timeout " }));
            controller.abort();
        }, timeout);
    });
}
let requestPromise = (url) => {
    return fetch(url, {
        signal: signal
    });
};
Promise.race([timeoutPromise(1000), requestPromise("https://www.baidu.com")])
    .then(resp => {
        console.log(resp);
    })
    .catch(error => {
        console.log(error);
    });

4. Резюме

Первый раз использую fetch в проекте, в процессе API-ориентированного программирования обнаружил, что у fetch нет настройки таймаута. Я впервые проверил документацию MDN и обратился к поисковой системе за вдохновением (copy+c). Некоторые друзья используют reject(new Error('network timeout')) в settimeout. На самом деле, это только заставляет внешний интерфейс воспринимать, что текущий запрос истек, и на самом деле не завершает запрос. Таким образом, вы должны использовать объект сигнала AbortSignal. Эта функция все еще находится на экспериментальной стадии, и ее следует использовать с осторожностью.

демонстрационный адрес [https://github.com/464884492] (https://github.com/464884492/blog/blob/master/demo/fetch/fetchdemo.js)