簡體   English   中英

可以與 fetch poll 異步直到滿足條件嗎? (幸免於難)

[英]can async with fetch poll until a condition is met? (survive rejection)

使用 fetch API 和 async/await,是否可以無限期地繼續輪詢,而不管 URL 是否可用? 我預計 URL 最終可能會變得可用,所以我想繼續嘗試直到滿足條件。 試圖想出一個最小可行的代碼示例,但我不確定我是否成功了:

// this is just a placeholder. It will eventually be a function 
// that evaluates something real. 
// Assume validContinue gets updated elsewhere.      
function shouldContinue() {
    return validContinue;
}
      
async function wonderPoll(someUrl) {

  // just a delay mechanism
  function wait(ms = 1000) {
    return new Promise(resolve => {
      setTimeout(resolve, ms);
    });
  }

  // the actual individual poll
  async function pollingFunction(url) {

    const response = await fetch(url, {
      cache: 'no-store'
    });

    if (response.ok) {
      return response;
    } else {
      Promise.reject(response);
    }

  }

  // allegedly keep polling until condition is met. 
  // But the rejected Promise is breaking out!
  while (shouldContinue()) {
    await wait();
    result = await pollingFunction(someUrl);
  }
  
  // when the fetch hits a rejected state, we never get here!
  console.log('done with the while loop, returning last successful result')

  return result;
}

const sampleUrl = 'https://get.geojs.io/v1/ip/country.json?ip=8.8.8.8';
const sampleUrl2 = 'http://totallybroken_fo_sho';

// swap the URL to test
wonderPoll(sampleUrl)
  .then((result) => {
    console.log('got a result', result)
  })
  .catch((err) => {
    console.log('got an error', err)
  });

我看到發生了什么(我認為)。 父調用最終執行輪詢函數,該函數拒絕 Promise。 繼續的條件理論上仍然滿足,但是拒絕會跳出While循環並直接向上發送到拒絕。 這一直傳播到原始/初始 Promise 的 catch 方法。 在已解決的 Promises 的情況下,它甚至不會命中在 While 循環之后出現的任何代碼。

我不知道如何防止這種情況發生。 我想我不明白攔截和解決承諾的語法。 當我用Promise.resolve(response)替換響應解析器中的Promise.resolve(response) ,它仍然拒絕到頂部。

如果我提供的 URL 有效,它將一直持續到不再滿足條件。


這是一個小提琴: https : //jsfiddle.net/gregpettit/qf495bjm/5/

要使用小提琴,“停止”按鈕模擬滿足條件,我提供了兩個不同的 URL,必須手動交換(通過傳遞 someUrl 或 someUrl2)以進行測試。

預期成績:

  • 具有良好的 URL,連續輪詢(必須在開發工具中挖掘網絡)直到滿足條件(按停止!)然后調用函數的“then”可以顯示結果。
  • 使用錯誤的 URL,連續輪詢直到滿足條件,然后調用函數的“catch”顯示錯誤

實際結果:

  • 陽性測試用例沒問題
  • 否定測試用例直接進入捕獲

您可以try…catch它以防止跳出循環。

while (shouldContinue()) {
  try {
    await wait();
    result = await pollingFunction(someUrl);
  } catch (e) {}
}

將 while 循環中的代碼更改為 try/catch,以便您可以捕獲錯誤

結果可以在沒有錯誤時保存一個值,或者在出現錯誤時保存一個原因

一旦循環停止,你要么返回值,要么拋出原因

如下

async function wonderPoll(someUrl) {

  // just a delay mechanism
  function wait(ms = 1000) {
    return new Promise(resolve => {
      setTimeout(resolve, ms);
    });
  }

  // the actual individual poll
  async function pollingFunction(url) {

    const response = await fetch(url, {
      cache: 'no-store'
    });

    if (response.ok) {
      return response;
    } else {
      Promise.reject(response);
    }

  }

  // allegedly keep polling until condition is met. But the rejected Promise is breaking out!
  while (shouldContinue()) {
    try {
      await wait();
      const value = await pollingFunction(someUrl);
      result = {value};
    } catch (reason) {
      result = {reason};
    }
  }
  // when the fetch hits a rejected state, we never get here!
  console.log('done with the while loop, returning last successful result')
  if (result.reason) {
    throw result.reason;
  }
  return result.value;
}

運行示例https://jsfiddle.net/twkbo9pg/

該示例在結果中包含status ,但這是不必要的(我從Promise.allSettled借用了代碼,但忘記刪除該屬性)

您可能想查看可觀察的流! 如果隨着時間的推移,您將有大量數據傳入,這就是 rxjs 的全部內容。

如果這感覺很笨拙,實際上有幾種方法可以做到這一點(有點像哈哈)。

import { ajax } from "rxjs/ajax";
import { duration } from "moment-timezone"; // I copied this from some old code... whatever.
import { catchError, map, share, switchMap } from "rxjs/operators";

const baseUrl = "http://foo.bar"
const base = (method, headers = {}) => ({
  method,
  headers: {
    Accept: "application/json",
    ...headers,
  },
  crossDomain: true,
  withCredentials: true,
})

const ajaxGet = url => ajax({ ...base("GET"), url })

export const userEpic = timer(0, duration(5, "minutes").asMilliseconds()).pipe(
  switchMap(() =>
    ajaxGet(`${baseUrl}/users`).pipe(
      map(({ response }) => getUsersSuccess(response)),
      catchError(e => of(getUsersError(e))),
    )
  ),
  share()
)

兩件事情

 } else {
            Promise.reject(response);
        }

應該返回那個。 它現在正在“偶然”工作。

 } else {
            return Promise.reject(response);
        }

其次, result = await pollingFunction(someUrl); 可能想要添加 .catch 到它: result = await pollingFunction(someUrl).catch(_=>null); 或任何可以在封閉while測試的東西

但我認為你可以簡化整個事情:

export async function wonderPoll(someUrl) {
    while (shouldContinue()) {
        await wait();

        const response = await fetch(someUrl, { cache: 'no-store' });

        if (response.ok)
            return response;
    }
    return Promise.reject(); // only if !shouldContinue()
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM