对列表中的每个对象进行API调用

时间:2019-07-13 14:52:35

标签: javascript reactjs

我有这种方法:

updateCustomers = (input) => {

    //let urls = input

    let urls=[{
        name: "localhost:8081",
        url: "http://localhost:8081"
    },
    {
        name: "localhost:8082",
        url: "http://localhost:8081"
    },
    {
        name: "localhost:8083",
        url: "http://localhost:8081"
    }]

    alert( urls.length)
    urls.map((url, index) => {

        let paramsNode = {
            customer: this.props.match.params.customer,
            environment: this.props.match.params.environment,
            action: 'check',
            node: url.name
        }
        console.log("url: "+url.name)
        console.log("***********************")
        this.gatewayService.manageServices(paramsNode, (callback) => this.checkServiceNode(callback, index, url))
    })

}

请忽略paramsNode变量,我要显示的是我想对列表的每个成员进行api调用。

这是我的api调用:

manageServices=(params,callback)=>{

    let url = this.baseUrl;

    if(params.customer == null || params.environment == null) {
        throw "The customer or environment parameter cant be null.";
    }

    url += "/" + params.customer + "/" + params.environment +  "/"+params.node  +"/configurations/manageServices/" + params.action;

    url = encodeURI(url);

    RestUtils.fetchJsonFromApi(url,callback);

}

这是RestUtils方法:

static fetchJsonFromApi(url, callback) {
    return fetch(url)
        .then(response => response.json())
        .then(json => {
            console.log("fetchJsonFromApi " + JSON.stringify(json))
            // making callback optional
            if (callback && typeof callback === "function") {
                callback(json);
            }
            return json;
        })
        .catch(error => {
            console.log(error)
        });
}

调用完成后,它将执行以下方法:

 checkServiceNode = (result, index,node) => {
    console.log("--------------------------")
    console.log("HERE"+node.name)
    console.log("##########################")
 }

我想做的是按以下顺序打印此值:

     url: localhost:8081
     ***********************
   --------------------------
    HERE localhost:8081
    ##########################

    url: localhost:8082
     ***********************
   --------------------------
    HERE localhost:8082
    ##########################

    url: localhost:8083
     ***********************
   --------------------------
    HERE localhost:8083
    ##########################

但是我得到的是(顺序总是随机的):

    url: localhost:8081
    ***********************
    url: localhost:8082
    ***********************
    url: localhost:8083
    ***********************

    --------------------------
    HERE localhost:8082
    ##########################

    --------------------------
    HERE localhost:8083
    ##########################
    --------------------------
    HERE localhost:8081
    ##########################

如何确保打印顺序?

3 个答案:

答案 0 :(得分:1)

Array.prototype.map不会在完成下一个API调用之前等待当前的API调用完成。因此,API调用完成的顺序取决于网络延迟和其他因素,这些因素使得顺序大多不确定。

如果要按顺序(一个接一个地)进行API调用,则可以编写一个函数,该函数将在上一个promise(api调用)解决后处理每个下一个url,例如,可以如下实现: / p>

const asyncSeries = (fn, items) => items.reduce((acc, item) => {
  return acc.then(collection =>
    fn(item).then(result =>
      collection.concat(result)
    )
  )
}, Promise.resolve([]));

要使其正常工作,您需要使发送api调用(manageServices)的函数返回承诺:

return RestUtils.fetchJsonFromApi(url,callback);

然后,您可以按以下顺序进行API调用:

asyncSeries((url, index) => {

  let paramsNode = {
    customer: this.props.match.params.customer,
    environment: this.props.match.params.environment,
    action: 'check',
    node: url.name
  }
  console.log("url: "+url.name)
  console.log("***********************")
  return this.gatewayService.manageServices(paramsNode, (callback) => this.checkServiceNode(callback, index, url))
}, urls)

答案 1 :(得分:0)

您正在使用fetch进行到端点的调用,并且fetch可以使用诺言。 Promise对象上有一个名为all的方法,该方法将一个promise列表作为参数,并在它们全部单独解析时进行解析。在then回调中,它作为第一个参数传递,其中包含每个承诺的已解决结果的列表。

Here is the documentation for the Promise.all method

这是如何使用它的基本示例。为了简化这种情况,我用一个模拟重写了fetch函数,该函数在随机的时间后解析。这样,每次运行时,每个承诺都会以不同的顺序解决。但是,result调用中的Promise.all返回的顺序与调用时的顺序相同。

function fetch(url) {
  var randomTimeout = Math.round(Math.random() * 1000, 0)
  return new Promise(function(resolve) {
    setTimeout(function() { resolve({url:url, timeout: randomTimeout}) }, randomTimeout);
  });
}

function callMultipleAPI(urlList) {
  return Promise.all(urlList.map(function (url) { return fetch(url); }));
}

var urlList = ['http://localhost:8081/', 'http://localhost:8082/', 'http://localhost:8083'];

callMultipleAPI(urlList)
  .then(function(result) { console.log(JSON.stringify(result, null, 2)); });

/*
Result:
[
  {
    "url": "http://localhost:8081/",
    "timeout": 869
  },
  {
    "url": "http://localhost:8082/",
    "timeout": 508
  },
  {
    "url": "http://localhost:8083",
    "timeout": 269
  }
]
*/

希望有帮助。

答案 2 :(得分:0)

已在2019年使用异步 / 等待

  let urls=[{
    name: "localhost:8081",
    url: "http://localhost:8081"
  },
  {
    name: "localhost:8082",
    url: "http://localhost:8081"
  }]

  const promises = []

  // make asynchronous api call for each endpoint
  // and save promise of call in array
  for(const url of urls) {
    promises.push(fetch(url.url))
    console.log(`endpoint ${url.name} called`)
  }

  const results = []

  // asyncronously await all of the calls and push result in same order
  for(const promise of promises) {
    results.push(await promise))
    // or use result right now
  }

  // use array of results as you need
  for(const result of results) {
    console.log(result)
  }

  // or with positioned access
  results.map( (result, pos) => {
    console.log(`endpoint ${urls[pos]} result: `, result)
  })