[英]How can I simplify multiple 'then's for asynchronous axios post method?
我使用axios POST method
使用連續的then
來通過API發布多個內容。
要修復硬編碼的then
,我嘗試使用for循環(使用let,for..of,Promise.all等),但它沒有按預期的那樣工作
File "C:\Python\Python3.6.3\lib\wsgiref\simple_server.py", line 35, in close
self.status.split(' ',1)[0], self.bytes_sent
AttributeError: 'NoneType' object has no attribute 'split'
錯誤(Django后端)。
這是源代碼(.vue文件)。
//defaultHttpClient is an axios call
const labelList = this.newLabel.text.split(" ");
this.copiedLabels = JSON.parse(JSON.stringify(this.newLabel));
async function putLabel(i, response, newLabel, copiedLabels, labels){
copiedLabels.text = newLabel.text.split(" ")[i]
await defaultHttpClient.post(`/v1/projects/${response.data.id}/labels`, copiedLabels)
//API call
}
//tried to make multiple API calls but this was the only way to make it possible.
defaultHttpClient.post('/v1/projects', payload)
.then((response) => {
window.location = `/projects/${response.data.id}/docs/create`;
return response;
})
.then((response)=> {
putLabel(0, response, this.newLabel, this.copiedLabels, this.labels);
return response;
})
.then((response)=> {
putLabel(1, response, this.newLabel, this.copiedLabels, this.labels);
return response;
})
.then((response)=> {
putLabel(2, response, this.newLabel, this.copiedLabels, this.labels);
return response;
})
我們如何才能簡化硬編碼then
S或使其更好地工作?
您可以使用async
和await
來簡化:
async function someFunction() {
try {
let response = await defaultHttpClient.post('/v1/projects', payload)
await putLabel(0, response, this.newLabel, this.copiedLabels, this.labels);
await putLabel(1, response, this.newLabel, this.copiedLabels, this.labels);
await putLabel(2, response, this.newLabel, this.copiedLabels, this.labels);
window.location = `/projects/${response.data.id}/docs/create`;
} catch(e) {
// put some error handling code here
}
}
就像您了解的那樣,您的原始代碼根本無法使用。 在您所有的putLabel()
調用都有機會執行之前, window.location
會更改當前頁面。 在將window.location
設置到新頁面之前,您需要完成所有想要完成的工作。
此外,你的所有.then()
處理程序不編碼以正確的順序才能執行,因為他們沒有等待每個putLabel()
來完成。 為此,您必須使用它們返回的承諾,但您只是忽略了這一點。
您可以將putLabel進一步簡化為:
function putLabel(i, response, newLabel, copiedLabels, labels) {
copiedLabels.text = newLabel.text.split(" ")[i]
return defaultHttpClient.post(`/v1/projects/${response.data.id}/labels`, copiedLabels)
//API call
}
重要的是要記住, await
暫停函數的內部執行,但是async
函數只要碰到第一個await
仍然會立即返回promise。 因此,您對putLabel()
await
沒有完成任何事情,也沒有阻止putLabel()
在.post()
調用完成之前返回。
似乎也沒有特別的原因, putLabel()
調用,即第二個等待第一個完成,並且它們可以全部並行運行。 如果是這種情況,則可以這樣運行它們:
async function someFunction() {
try {
let response = await defaultHttpClient.post('/v1/projects', payload)
await Promise.all([
putLabel(0, response, this.newLabel, this.copiedLabels, this.labels),
putLabel(1, response, this.newLabel, this.copiedLabels, this.labels),
putLabel(2, response, this.newLabel, this.copiedLabels, this.labels)
]);
window.location = `/projects/${response.data.id}/docs/create`;
} catch(e) {
// put some error handling code here
}
}
const apicall = async () => {
const res1 = await defaultHttpClient.post('/v1/projects', payload)
window.location = `/projects/${res1.data.id}/docs/create`;
const res2 = putLabel(0, res1, this.newLabel, this.copiedLabels, this.labels);
const res3 = putLabel(1, res2, this.newLabel, this.copiedLabels, this.labels);
const res4 = putLabel(2, res3, this.newLabel, this.copiedLabels, this.labels);
return res4;
}
調用此函數,這里我們使用async await,使代碼更簡單易讀,它將返回一個promise。
如果您在python中遇到錯誤,則應驗證有效載荷(要發送到python后端的載荷)正確。 Javascript部分本身並沒有多大用處。
但是,通過避免在重定向后再執行其他操作,並嘗試使用Promise.all
而不是順序的方法來並行執行對putLabel
的后續調用,可以對代碼進行一些改進,這是如果await
一個之后使用多個await
調用后得到的結果另一個
defaultHttpClient.post('/v1/projects', payload).then(response => {
// according to your code, in all calls of `putLabel`
// you're using the first response which you receive from the
// `/v1/projects` endpoint
Promise.all([
putLabel(0, response, this.newLabel, this.copiedLabels, this.labels),
putLabel(1, response, this.newLabel, this.copiedLabels, this.labels),
putLabel(2, response, this.newLabel, this.copiedLabels, this.labels)
]).then(() => {
// all promises have finished so we can redirect
window.location = `/projects/${response.data.id}/docs/create`;
})
})
似乎您具有使用阻塞式編程語言的背景知識,但是JS
是non-blocking
,這意味着您的代碼不會自上而下執行, 除非它在async
函數內部且await
任何異步函數調用之前await
(處理非阻塞式的最佳方法)屏蔽語言背景)。
不幸的是,這在函數外部不起作用,因此您需要將API調用放入函數主體中。 據我所知,您可以將計數器抽象為for循環,這樣:
async function apiCalls(max = 2) {
let response = await defaultHttpClient.post('/v1/projects', payload)
window.location = `/projects/${response.data.id}/docs/create`
for (let i = 0; i <= max; i++) {
response = await putLabel(i, response, this.newLabel, this.copiedLabels, this.labels)
}
}
但是這樣一來,您的API調用Promise.all
順序運行,這意味着總的函數調用時間為所有調用的總和,但是如果您不需要下一個調用中上一個調用的響應,則可以按照其他人的建議使用Promise.all
。 這樣,您的函數調用時間將與最長的API調用一樣長(所有調用同時進行),因此:
async function apiCalls(max = 2) {
let response = await defaultHttpClient.post('/v1/projects', payload)
window.location = `/projects/${response.data.id}/docs/create`
const reqs = []
for (let i = 0; i <= max; i++) {
reqs.push(putLabel(i, response, this.newLabel, this.copiedLabels, this.labels))
}
await Promise.all(reqs)
}
使用try/catch
可以在async
函數中捕獲和拋出/拋出錯誤(在您的情況下建議)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.