简体   繁体   English

将异步函数应用于JavaScript Promise中的每个元素

[英]Apply async function to each element in JavaScript Promise

Can't quite understand how to do this in Promises, as I started learning about them today. 我今天开始学习有关Promises的方法时,还不太了解如何做到这一点。 What I am trying to do is that: 我想做的是:

  • Send a GET request and iterate until final page is reached (I can do this) 发送GET请求并进行迭代,直到到达最后一页(我可以这样做)
  • Concatenate response elements to an array (an array of JSON objects, also done) 将响应元素连接到一个数组(一个JSON对象数组,也完成)
  • For each element in this array, perform async operation such as image upload and database query (stuck here) 对于此数组中的每个元素,执行异步操作,例如图像上传和数据库查询(卡在此处)

Here's what I have done so far: 到目前为止,这是我所做的:

Following function iterates over all pages. 以下函数遍历所有页面。

function getAllCountries(requestURL, pageNr, countries) {
  return Request({
    'method': 'GET',
    'uri': requestURL,
    'json': true,
  }).then((response) => {
    if (!countries) {
      countries = [];
    }

    countries = countries.concat(response.data);
    const meta = response.meta;

    if (pageNr < meta['pagination']['total_pages']) {
      pageNr += 1;
      let formattedLink = Format(BASE_URL, API_TOKEN, pageNr);
      return getAllCountries(formattedLink, pageNr, countries);
    }

    return countries;
  });
}

Here is where I am having trouble: 这是我遇到麻烦的地方:

getAllCountries(formattedLink, pageNr)
  .then((countries) => {
    // will call handleCountry method for each country here

    // how do I handle the callback to/from handleCountry here?
    // that is wrong
    // countries.map(handleCountry);
  })
  .then(() => {
    console.log('Handled all countries');
    return res.sendStatus(200);
  })
  .catch((error) => {
    console.log(error);
    return res.sendStatus(500);
  });

Here is how handleCountry function is: 这是handleCountry函数的方式:

function handleCountry(country, callback) {
  // do stuff here
  if (!country["extra"]) {
    app.models.Country.upsert(countryJson, callback);
  } else {
    // do async stuff here, image upload etc with Async.auto
    Async.auto({
      'uploadImage': (autoCallback) => {
        uploadImage(autoCallback);
      }
      'updateOnDb': ['uploadImage', (results, autoCallback) => {
        // do stuff
        app.models.Country.upsert(countryJson, autoCallback);
      }
    }, callback);
  }
}

What should I do here? 我该怎么办? The order of handling countries is not important, by the way. 顺便说一句,处理国家的顺序并不重要。

function getAllCountries(requestURL, pageNr, countries) {
    Request({
        'method': 'GET',
        'uri': requestURL,
        'json': true,
    }).then((response) => {
        if (!countries) {
        countries = [];
        }

        countries = countries.concat(response.data);
        const meta = response.meta;

        if (pageNr < meta['pagination']['total_pages']) {
            pageNr += 1;
            let formattedLink = Format(BASE_URL, API_TOKEN, pageNr);

            // declaring array to be passed inside promise.all
            let countriesPromises = [];


            // creating promises for each country
            countries.forEach(function(country) {
                countriesPromises.push(new Promise(function(){
                    handleCountry(country,callback);
                })
            });

        }

        // callback for all countries.
        Promise.all(countriesPromises)
            .then(() => {
                console.log('Handled all countries');
                return res.sendStatus(200);
            })
            .catch((error) => {
                console.log(error);
                return res.sendStatus(500);
            })
    }   

}

After getting all the countries we create promise for each strong them in an array and finally passing them into promise.all() which allows us to bind callbacks for completion for all promises. 获取所有国家/地区后,我们将为每个强大的国家/地区创建一个数组,并最终将它们传递给promise.all(),这使我们可以绑定回调以完成所有promise。 Note that i have removed all return statement and getAllCountries is no longer thenable, we have implemented the callbacks inside of getAllCountries itself. 请注意,我已经删除了所有return语句,并且getAllCountries不再可用,我们已经在getAllCountries本身内部实现了回调。 You may segregate it as per your need ahead. 您可以根据自己的需要对其进行隔离。

Problem is that handleCountryAsync() isn't playing the "promises game" - it accepts a callback instead of returning a promise. 问题是handleCountryAsync()没有玩“承诺游戏”-它接受回调而不是返回承诺。

You could promisify by rewriting handleCountry() but it's just as simple to leave handleCountry() intact and write an adaptor, handleCountryAsync() as follows : 您可以通过重写handleCountry()来实现承诺,但是保持handleCountry()完整并编写一个适配器handleCountryAsync()就像这样简单:

function handleCountryAsync(country) {
    return new Promise((resolve, reject) => {
        try {
            handleCountry(country, (...args) => {
                resolve(args); // promises can be fulfilled only with a single value, but multiple arguments can be delivered as an array.
            });
        }
        catch(error) {
            reject(error);
        }
    });
}

Now, the need for an overt callback in the higher level code disappears and countries.map() can return an array of promises to Promise.all() : 现在,在更高级别代码中对公开回调的需求消失了, countries.map()可以向Promise.all()返回一个promise数组:

getAllCountries(formattedLink, pageNr)
.then(countries => Promise.all(countries.map(handleCountryAsync)))
.then(() => {
    console.log('Handled all countries');
    return res.sendStatus(200);
})
.catch((error) => {
    console.log(error);
    return res.sendStatus(500);
});

That's the essence of it ayway. 这就是它的本质。 Other considerations revolve chiefly around error handling. 其他考虑主要围绕错误处理。 For example, you have a design decision - whether to swallow errors or allow a single failure of handleCountryAsync to give rise to a 500. As writen above, it is the latter. 例如,您有一个设计决策-是吞下错误还是允许handleCountryAsync的单个故障产生500。如上所述,后者就是后者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM