web-dev-qa-db-ja.com

Javascript Promises:すべてのオブジェクトキー配列を反復処理してから解決します

私はこのJSオブジェクトを持っています:

let setOfWords = {
    "nouns": [
        "work",
        "construction",
        "industry"
    ],
    "verbs": [
        "work"
    ],
}

RESTリソースを呼び出すGoogle翻訳APIを使用しているので、各翻訳の応答を待ってから、同じオブジェクト構造を翻訳された単語で解決する必要があります。

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

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

6
hackerrdave

個々の約束はPromise.all()で集約する必要があり、基本的にそれが欠けています。

ただし、Googleサービスへの呼び出し回数を減らすことで、より良い結果が得られます。

Google translate APIを使用すると、呼び出しごとに1つの単語ではなく単語の配列を渡すことで、複数のテキスト文字列を1回のヒットで翻訳できます。これにより、パフォーマンス上の利点が得られますが、おそらく価格上の利点はありません。 「通話ごと」ではありません。

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);
});
1
Roamer-1888

@ 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();

そして、あなたは「translatedObj」であなたが望むものを手に入れるでしょう。

0
Neeraj Wadhwa