如何简化异步axios post方法的多个“ then”?

时间:2019-08-01 05:35:55

标签: javascript asynchronous promise async-await axios

我使用axios POST method通过API使用连续的then发布多个内容。

要修复硬编码的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或使其更好地工作?

4 个答案:

答案 0 :(得分:0)

您可以使用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
      }
 }

仅您所了解,原始代码根本无法使用。在您所有的window.location调用都有机会执行之前,putLabel()会更改当前页面。在将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。因此,您在await中的putLabel()并没有完成任何事情,也没有阻止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
      }
 }

答案 1 :(得分:0)

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。

答案 2 :(得分:0)

如果您在python中遇到错误,则应验证有效载荷(您要发送到python后端的载荷)是正确的。 Javascript部分本身并没有多大用处。

但是,通过避免在重定向后执行其他操作并尝试使用putLabel而不是顺序地并行地对Promise.all进行后续调用,可以对代码进行一些改进,这就是您要做的如果您一个接一个地使用多个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`;
  })
}) 

答案 3 :(得分:0)

似乎您具有阻止编程语言的背景,但是ID --- 1 2 2 3 3 3 4 4 4 4 JS,这意味着您的代码不会自上而下执行除非,它位于{{1} }在进行任何异步函数调用之前使用non-blocking函数(处理具有阻塞语言背景的非阻塞的最佳方法)。

不幸的是,这在函数外部不起作用,因此您需要将API调用放入函数主体中。据我所知,您可以将计数器抽象为for循环,这样:

async

但是通过这种方式,您的API调用将按顺序运行,这意味着总的函数调用时间是所有调用的总和,但是如果您不需要下一个调用中上一个调用的响应,则可以使用{{1} },由其他人建议。这样,您的函数调用时间与最长的API调用(所有调用同时完成)一样长,因此:

await

使用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) } } 可以在Promise.all函数内捕获并抛出/抛出错误(在您的情况下建议使用)。