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

时间:2017-09-17 21:59:16

标签: javascript node.js promise es6-promise

我很难理解如何在Promises中做到这一点,因为我今天开始了解它们。我想做的是:

  • 发送GET请求并进行迭代,直到达到最终页面(我可以这样做)
  • 将响应元素连接到数组(JSON对象数组,也已完成)
  • 对于此数组中的每个元素,执行异步操作,如图像上载和数据库查询(卡在此处)

这是我到目前为止所做的事情:

以下函数遍历所有页面。

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

这是我遇到麻烦的地方:

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

以下是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);
  }
}

我该怎么办?顺便说一句,处理国家的顺序并不重要。

2 个答案:

答案 0 :(得分:0)

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

}

在获得所有国家之后,我们为每个国家创建了承诺,并在数组中最终将它们传递给promise.all(),这允许我们绑定回调以完成所有承诺。请注意,我已经删除了所有return语句并且getAllCountries不再可用,我们已经在getAllCountries本身内部实现了回调。您可以根据自己的需要将其分开。

答案 1 :(得分:0)

问题是handleCountryAsync()没有玩#34;承诺游戏&#34; - 它接受回调而不是返回承诺。

您可以通过重写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);
        }
    });
}

现在,更高级别代码中的公开回调需求消失,countries.map()可以向Promise.all()返回一系列承诺:

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

这就是它的本质。其他考虑因素主要围绕错误处理。例如,您有一个设计决策 - 是否吞下错误或允许handleCountryAsync单个失败产生500.如上所述,它是后者。