Обещания Javascript: переберите все массивы ключей объекта и затем разрешите
У меня есть этот объект JS:
let setOfWords = {
"nouns": [
"work",
"construction",
"industry"
],
"verbs": [
"work"
],
}
Я использую API Google Translate, который вызывает ресурс REST, поэтому мне нужно дождаться ответа каждого перевода и затем разрешить ту же структуру объекта, но с переведенными словами.
function translateByCategory(){
let translatedObj = {};
return new Promise(function(resolve, reject){
Object.keys(obj).forEach(function(category){
if (translatedObj[category] == undefined) {
translatedObj[category] = [];
}
setOfWords.forEach(function(word){
google.translate(word, 'es', 'en').then(function(translation){
translatedObj[category].push(translation.translatedText);
});
});
// return the translatedObj until all of the categories are translated
resolve(translatedObj);
});
});
}
3 ответа
Ты можешь использовать Promise.all()
ждать выполнения всех обещаний (или первого отказа)
var translateRequests = [];
Object.keys(setOfWords).forEach(function(category){
setOfWords[category].forEach(function(word){
translateRequests.push(google.translate(word, 'es', 'en'));
});
});
});
Promise.all(translateRequests).then(function(translateResults){
//do something with all the results
});
Смотрите документы здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Индивидуальные обещания должны быть объединены с Promise.all()
и в принципе, это то, что не хватает.
Но вы можете добиться большего, уменьшив количество звонков в службу Google.
Google translate API позволяет переводить несколько текстовых строк одним ударом, передавая массив слов вместо одного слова за вызов, что дает вам преимущество в производительности, хотя, вероятно, не в цене - Google в настоящее время взимает плату за свою услугу перевода "за символ", не "за звонок".
Я не могу найти документацию для google.translate()
но, с некоторыми допущениями, вы можете написать:
function translateByCategory(obj, sourceCode, targetCode) {
let translatedObj = {};
var promises = Object.keys(obj).map(function(key) {
return google.translate(obj[key], sourceCode, targetCode).then(function(translations) {
translatedObj[key] = translations.map(function(t) {
return t.translatedText || '-';
});
}, function(error) {
translatedObj[key] = [];
});
});
return Promise.all(promises).then(function() {
return translatedObj;
});
}
Если это не сработает, то в этой документации объясняется, как напрямую вызвать службу перевода Google RESTful.
Вы должны быть в состоянии написать:
function translateTexts(baseParams, arrayOfStrings) {
let queryString = baseParams.concat(arrayOfStrings.map(function(str) {
return 'q=' + encodeURIComponent(str);
})).join('&');
return http.ajax({ // some arbitrary HTTP lib that GETs by default.
url: 'https://translation.googleapis.com/language/translate/v2?' + queryString,
}).then(function(response) {
return response.data.translations.map(function(t) {
return t.translatedText || '-';
});
}, function(error) {
translatedObj[key] = []; // on error, default to empty array
});
}
function translateByCategory(obj, sourceCode, targetCode) {
let baseParams = [
'key=' + MY_API_KEY, // from some outer scope
'source=' + sourceCode, // eg 'en'
'target=' + targetCode // eg 'es'
];
let translatedObj = {};
let promises = Object.keys(obj).map(function(key) {
return translateTexts(baseParams, obj[key]).then(function(translations) {
translatedObj[key] = translations;
}, function(error) {
translatedObj[key] = []; // on error, default to empty array
});
});
return Promise.all(promises).then(function() {
return translatedObj;
});
}
В любом случае, позвоните следующим образом:
let setOfWords = {
"nouns": [
"work",
"construction",
"industry"
],
"verbs": [
"work"
],
};
translateByCategory(setOfWords, 'en', 'es').then(function(setOfTranslatedWords) {
console.log(setOfTranslatedWords);
});
Метод, предложенный hackerrdave, можно изменить, чтобы сделать его более совместимым с функцией асинхронного ожидания в JavaScript, сделайте это следующим образом:
function translateByCategory(){
return new Promise(function(resolve, reject){
var translateRequests = [];
Object.keys(setOfWords).forEach(function(category){
setOfWords[category].forEach(function(word){
translateRequests.push(google.translate(word, 'es', 'en'));
});
});
Promise.all(translateRequests).resolve(resolve(translateRequests));
});
}
Так что теперь вы можете сделать что-то вроде:
let translatedObj = await translateByCategory();
И вы получите то, что вы хотите в "TranslateObj".