异步/等待功能中的JavaScript Promise解决了最终的响应数组

时间:2018-11-22 07:08:54

标签: javascript node.js recursion promise

在JavaScript和Promises中,我是一个新手。 我正在尝试构建从API获得的对象数组。

为此,我在文件MyFile.js中构建了两个函数。

第一个返回axios承诺的承诺。

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部分,在这里它解析包含所有promise的结果(值不是状态)的数组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结果(无需使用Promise.all()来进行意向调用,而不是并行调用)我想这对性能非常有用吗?)然后从其他任何地方调用此函数时,都可以在then部分中检索该响应。 请记住,我实际上是Promise和JavaScript的新手(我更像是Python专家)。

让我知道我的问题是否还不清楚。 我已经挠头了两天,感觉好像我在盘旋。

感谢您成为一个很棒的社区!

3 个答案:

答案 0 :(得分:1)

有一些问题。一个是除非输入resolve块,否则您永远不会Promise开头的else。另一个是您应该每次都返回递归get_data调用,以便可以将其与初始Promise正确地链接起来。您也可以考虑避免explicit promise construction antipattern-get_items已经返回Promise,因此无需构造另一个(与get_items的内部相同,{{1} }通话也会返回axios

您可能会考虑一个普通的Promise循环,重新分配while字符串,直到出现错误为止:

next_url

请注意,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,因为这将使调用者很难检测到错误。

答案 1 :(得分:0)

这有点未经测试

def validate(name):
    try:
        codecs.lookup(name)
        return True
    except LookupError:
        return False

基本上,它使事情变得更整洁。我建议看更多有关Promises的示例,并了解其优势以及何时缓解等待/异步。要记住的一件事是,如果您返回一个Promise,它将遵循整个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; } 链,并且它始终将返回一个Promise,其值为最后一个then ..如果这样有意义: )

答案 2 :(得分:0)

另一种实现方法是完全不使用异步,而仅递归地返回一个promise:

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
};

如“某些性能”所述;您不需要在每个级别都进行捕获,如果您希望getData因错误而被拒绝。堆栈只需要捕获一次即可。

但是;如果您有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
};