在等待 json 响应时未兑现诺言

Uncaught in promise while waiting for json response

我第一次在 JS 中实现 Promises,并且在 运行 下面的代码中未捕获到控制台日志中的 Promise 异常。

function data_present() {
        return new Promise((resolve, reject) => {
            fetch(api)
            .then(response => response.json())
            .then(message => { 
                console.log(message)
                if(message && Object.keys(message).length != 0) {
                    resolve()
                }
                else {
                    reject()
                }
            })
        })
    }

我正在如下处理主函数中 promise return 值的结果,但尚未收到未捕获的 promise 消息:

function main() {
    data_present().then(() => {
        load_graph()
    }).catch(() => {
        data_present()
    })
}

data_present() 背后的逻辑是等到我们在 API 端点得到一个非空的 JSON 响应,如果 JSON 则继续轮询它响应为空。

我得到的异常如下:

Uncaught (in promise) undefined
(anonymous) @ index.js:34
Promise.then (async)
(anonymous) @ index.js:29
data_present @ index.js:26
(anonymous) @ index.js:56
Promise.catch (async)
getParametersData @ index.js:55
onclick @ (index):92

fetch已经returns一个承诺。所以你不应该再包装它(我在我的例子中包括了这个)。错误来自对函数的第二次调用,如下面的第二个 catch 块所述

function data_present() {
  return fetch(api)
    .then(response => response.json())
    .then(message => {
      console.log(message)
      if (!message || Object.keys(message).length === 0) {
        throw new Error('something went wrong');
      } 
    })
}

function main() {
  data_present()
    .then(() => {
      load_graph()
    }).catch(() => {
      return data_present() // the promise which is returned here was not caught in your example
    })
    .catch(() => {
      // another error
    })
}

您可能会考虑使用一个函数来获取、解析和 return 来自 API 的 JSON(无需将您的 fetch 包装在一个 promise 中因为它已经 returns 一个),并使用您的轮询功能来检查 returned 数据。如果正确则调用一个函数,否则再次轮询 getData。如果有一个 API 错误记录,而不是。

我这里用的是async/await,原理是一样的

// Simulates an API
// If the random number is a modulo of 5 set data
// to an object with a key/value pair, otherwise
// it set it to an empty object. If the random number
// is a modulo of 9 send an error, otherwise send the data.
function mockFetch() {
  return new Promise((res, rej) => {
    const rnd = Math.floor(Math.random() * 20);
    const data = rnd % 5 === 0 ? { name: 'Bob' } : {};
    setTimeout(() => {
      if (rnd % 9 === 0) rej('Connection error');
      res(JSON.stringify(data));
    }, 2000);
  });
}

// `getData` simply gets a response from the API and parses it.
// I had to use JSON.parse here rather that await response.json()
// because I'm not using the actual fetch API.
async function getData() {
  const response = await mockFetch();
  return JSON.parse(response);
}

// The `poll` function does all the heavy-lifting
// first we initialise `count`
async function poll(count = 1) {

  console.log(`Polling ${count}`);

  // Try and get some data. If it's not an empty object
  // log the name (or in your case call loadGraph),
  // otherwise poll the API again after two seconds.
  // We wrap everything in a `try/catch`.
  try {

    const data = await getData();

    if (data && data.name) {
      console.log(data.name); // loadGraph
    } else {
      setTimeout(poll, 2000, ++count);
    }

  // If the API sends an error log that instead
  // and poll again after five seconds
  } catch (err) {
    console.log(`${err}. Polling again in 5 seconds.`);
    setTimeout(poll, 5000, 1);
  }

}

poll();

这是版本 :

function mockFetch() {
  return new Promise((res, rej) => {
    const rnd = Math.floor(Math.random() * 20);
    const data = rnd % 5 === 0 ? { name: 'Bob' } : {};
    setTimeout(() => {
      if (rnd % 9 === 0) rej('Connection error');
      res(JSON.stringify(data));
    }, 2000);
  });
}

async function getData() {
  const response = await mockFetch();
  return JSON.parse(response);
}

async function delay(time) {
  return new Promise(res => setTimeout(res, time));
}

async function poll(count = 1) {

  do {

    console.log(`Polling ${count}`);

    try {
      const data = await getData();
      if (data && data.name) return data;
      await delay(2000);
    } catch (err) {
      console.log(`${err}. Polling again in 5 seconds.`);
      await delay(5000);
    }

    ++count;

  } while (count < 10);

  console.log(`Reached poll limit - ${count}.`);
  return false;

}

async function main() {
  console.log('First');
  console.log(await poll());
  console.log('Second');
}

main();