簡體   English   中英

如何簡化異步axios post方法的多個“ then”?

[英]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或使其更好地工作?

您可以使用asyncawait來簡化:

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

似乎您具有使用阻塞式編程語言的背景知識,但是JSnon-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM