在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
在做的事情)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专家)。
让我知道我的问题是否还不清楚。 我已经挠头了两天,感觉好像我在盘旋。
感谢您成为一个很棒的社区!
答案 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
};