JavaScript的无极里面异步/ AWAIT功能解决的反应最终阵列(JavaScript Pro

2019-09-26 14:44发布

我在JavaScript和承诺相当新手。 我试图建立我从API获取对象的数组。

要做到这一点,我在一个文件中创建两个函数MyFile.js

第一个返回当爱可信承诺解决的承诺。 它的

function get_items (url) {
    return new Promise((resolve, reject) => {
        let options = {
            baseURL: url,
            method: 'get'
        }
        axios(options)
            .then(response => {
                resolve(response.data)
            })
            .catch(error => {
                reject(error.stack)
            })
    })
}

第二个看起来像这样:

let output = []
let next_url = 'https://some_url.com/api/data'
async function get_data () {
    try {
        let promise = new Promise((resolve, reject) => {
            if (next_url) {
                get_items(next_url)
                    .then(response => {
                        output.push(...response.results)
                        if (response.next) {
                            next_url = response.next
                            console.log('NEXT_URL HERE', next_url)
                            get_data()
                        } else {
                            console.log('else')
                            next_url = false
                            get_data()
                        }
                    })
                    .catch(error => {
                        reject(error.stack)
                    })
            } else {
                console.log('before resolve')
                resolve(output)
            }
        })
        return await promise
    } catch(e) {
        console.log(e)
    }
}

这也正是我磨我的牙齿。 我想我明白这个功能的,就是:

  • 它返回一个承诺的价值(这是我的理解return await promise是做)
  • 这是一个递归函数。 所以,如果有一个next_url,功能上继续。 但是,如果没有,它被称为最后一次去到else地方解决了阵列部分output包含了所有承诺的结果(值不是状态)。 至少,当我执行它,并为您我的理智检查用console.log我写的,它的工作原理。

因此, output填充数据,这就是伟大的。

但是,当我调用此函数从另一个文件MyOtherFile.js ,就像这样:

final_output = []
MyFile.get_data()
    .then(result => {
        console.log('getting data')
        final_output.push(...result)
    })

它从未进入的then一部分。 当我CONSOLE.LOG MyFile.get_data()这是一个悬而未决的承诺。

所以,我想做些什么,是能够使get_data()等待所有的承诺产生(不使用Promise.all(),有在意甲电话,而不是并行的,它会为演出太好了,我猜?),然后能够取回在该响应then从其他地方调用这个函数时的一部分。 请记住,我真的在承诺和JavaScript一般一个新手(我更Python的家伙)。

让我知道如果我的问题不够清楚。 我一直在抓我的头两天,感觉就像我在圈我跑。

感谢您成为一个真棒社区!

Answer 1:

有几个问题。 其中之一是,你永远不resolve最初Promise ,除非else输入块。 另一个原因是,你应该返回递归get_data调用每一次,使之能与最初的正确链接Promise 。 您也可以考虑避免了明确的承诺,建设反模式 - get_items已经返回一个Promise ,所以没有必要建立另一个(同为内部get_itemsaxios调用返回Promise七大洲)。

你可能会考虑一个简单的while循环,重新分配next_url串,直到它的falsey:

function get_items (baseURL) {
  const options = {
    baseURL: url,
    method: 'get'
  }
  // return the axios call, handle errors in the consumer instead:
  return axios(options)
    .then(res => res.data)
}

async function get_data() {
  const output = []
  let next_url = 'https://some_url.com/api/data'
  try {
    while (next_url) {
      const response = await get_items(next_url);
      output.push(...response.results)
      next_url = response.next;
    }
  } catch (e) {
    // handle errors *here*, perhaps
    console.log(e)
  }
  return output;
}

需要注意的是.catch将导致Promise拒绝转化Promise解决一个-你不想.catch无处不在,因为这将很难让呼叫者检测错误。



Answer 2:

这是一个有点未经测试

const api_url = 'https://some_url.com/api/data';

get_data(api_url).then((results) => {
  console.log(results);
}).catch((error) => {
   // console.error(error);
});

function get_items (url) {
  const options = {
    baseURL: url,
    method: 'get'
  };

  return axios(options).then((response) => response.data);
}

async function get_data(next_url) {
  const output = [];

  while (next_url) {
    const { results, next } = await get_items(next_url);
    output.push(...results);
    next_url = next;
  }

  return output;
}

基本上,它使事情有点整洁。 我建议去看待承诺和优势以及何时缓解的await /异步更多的例子。 有一点要记住,如果你返回一个承诺,它会按照整个then链,它总是与最后的值返回无极then ..如果是有道理的:)



Answer 3:

这样做的另一种方法是在所有不使用异步,只是递归返回一个承诺:

const getItems = (url) =>
  axios({
    baseURL: url,
    method: 'get',
  }).then((response) => response.data);

const getData = (initialUrl) => {
  const recur = (result, nextUrl) =>
    !nextUrl
      ? Promise.resolve(result)
      : getItems(nextUrl).then((data) =>
          recur(result.concat([data.results]), data.next),
        );
  return recur([],initialUrl)
    .catch(e=>Promise.reject(e.stack));//reject with error stack
};

作为CertainPerformance注意; 你不需要赶在每一个级别,如果你想的getData与error.stack你只需要抓住它曾经拒绝。

然而; 如果你有100个下一URL和其中99人很好,但只有最后一个失败的,你想在保持迄今为止的结果,所以你可以再次尝试的方式来拒绝?

如果你这样做,则代码可能是这个样子:

const getData = (initialUrl) => {
  const recur = (result, nextUrl) =>
    !nextUrl
      ? Promise.resolve(result)
      : getItems(nextUrl)
        .catch(e=>Promise.reject([e,result]))//reject with error and result so far
        .then((data) =>
          recur(result.concat([data.results]), data.next),
        );
  return recur([],initialUrl);//do not catch here, just let it reject with error and result
};


文章来源: JavaScript Promise inside async/await function resolve final array of responses