如何中止一批异步获取请求?

ben*_*nwl 2 javascript reactjs fetch-api

我目前有一个坐标列表,我用它来获取附近的徒步旅行。假设我将列表状态更新为新坐标,但先前坐标的提取请求未完成 - 如何取消对先前坐标发出的所有提取请求,而仅根据新坐标调用新的提取请求?

我尝试实现,AbortController但它可能不起作用,因为它没有取消“批量”的获取请求,而只是取消单个获取请求。我的代码如下:

  let abortController = new AbortController();
  const getNearbyHikes = async (coordinates) => {
    abortController.abort();
    abortController = new AbortController();
    for (const coord of coordinates) {
      if (coord) {
        try {
          const { lat, lng } = cord.coordinates
          const response = await fetch(
            'http://localhost:5000/category/' + lat + "/" + lng + '/' + searchCategory,
            {signal: abortController.signal}
          )
          const result = await response.json();
          setHikes((prevState) => [...prevState, ...result.businesses])
        } catch (error) {
          if(error.name === 'AbortError'){
            return;
          }
          throw error
        }

      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

另外,我想在获得加息时更新我的​​用户界面,这样我的网络应用程序看起来并不很慢,所以我避免使用Promise.all. 非常感谢任何建议或帮助。

T.J*_*der 5

取消的主要问题是您错误地提供了信号fetch。您提供信号作为第二个参数,但fetch需要一个带有signal属性的“init”对象。

不过,正如 @Keith 指出的那样,您当前的代码一次只能进行一个调用。这会起作用,但您可能会从并行进行调用中受益。

像这样的东西:

const getOneResult = async ({ lat, lng }, signal) => {
    try {
        const response = await fetch(
            "http://localhost:5000/category/" +
                lat +
                "/" +
                lng +
                "/" +
                searchCategory, // *** Where does this come from?
            { signal }
        );
        if (signal && signal.aborted) {
            throw new DOMException("Request cancelled", "AbortError");
        }
        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }
        return response.json();
    } catch (error) {
        if (error.name === "AbortError") {
            return null;
        }
    }
};
const getNearbyHikes = async (coordinates, signal) => {
    controller.abort();
    controller = new AbortController();
    const results = await Promise.all(
        coordinates.map((coord) => getOneResult(coord.coordinates, signal))
    );
    if (signal && signal.aborted) {
        return;
    }
    const businesses = [];
    for (const result of results) {
        businesses.push(...result.businesses);
    }
    setHikes((prevState) => [...prevState, ...businesses]);
};
Run Code Online (Sandbox Code Playgroud)

最后,我会让调用者提供信号,而不是对所有调用使用全局信号getHikes

const getOneResult = async ({ lat, lng }, signal) => {
    try {
        const response = await fetch(
            "http://localhost:5000/category/" +
                lat +
                "/" +
                lng +
                "/" +
                searchCategory, // *** Where does this come from?
            { signal }
        );
        if (signal && signal.aborted) {
            throw new DOMException("Request cancelled", "AbortError");
        }
        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }
        return response.json();
    } catch (error) {
        if (error.name === "AbortError") {
            return null;
        }
    }
};
let controller = new AbortController();
const getNearbyHikes = async (coordinates) => {
    controller.abort();
    controller = new AbortController();
    const results = await Promise.all(
        coordinates.map((coord) => getOneResult(coord.coordinates, signal))
    );
    if (signal && signal.aborted) {
        return;
    }
    const businesses = [];
    for (const result of results) {
        businesses.push(...result.businesses);
    }
    setHikes((prevState) => [...prevState, ...businesses]);
};
Run Code Online (Sandbox Code Playgroud)

然后调用者控制中止请求。但前者可能适合您的用例。


response.ok旁注:您会看到我在其中添加了一张支票。您的代码假设由于fetch承诺已履行,HTTP 调用有效,但不幸的是,这是 API 中的一个枪:它仅在网络fetch故障时拒绝其承诺,而不是在 HTTP 失败时拒绝。您必须明确检查后者。