javascript लूप के लिए एक वादे कैसे लौटाएंगे(जो प्रत्येक चलन पर एक वादा पैदा करता है) पूरा हो गया है?




angularjs for-loop (5)

मुझे अपने वादा रिटर्न कोड में कोई समस्या है, मेरे पास फंक्शन getTagQuotes जिसमें एक लूप है जिसमें एक से अधिक कॉल कर सकते हैं, एपीआई को एक सरणी में डेटा वापस करने के लिए।

इसके लिए मेरा कोड नीचे कैसे शुरू होता है:

// If there are tags, then wait for promise here:
if (tags.length > 0) {

    // Setting promise var to getTagQuotes:
    var promise = getTagQuotes(tags).then(function() {
        console.log('promise =',promise);

        // This array should contain 1-3 tags:
        console.log('tweetArrayObjsContainer =',tweetArrayObjsContainer);

        // Loop through to push array objects into chartObj:
        for (var i=0; i<tweetArrayObjsContainer.length; i++) {
            chartObj.chartData.push(tweetArrayObjsContainer[i]);
        }

        // Finally draw the chart:
        chartDirective = ScopeFactory.getScope('chart');
        chartDirective.nvd3.drawChart(chartObj.chartData);
    });
}

वादा रिटर्न के साथ मेरी getTagQuotes कार्य करती है:

function getTagQuotes(tags) {
    var deferred = $q.defer(); // setting the defer
    var url      = 'app/api/social/twitter/volume/';

    // My for loop, which only returns ONCE, even if there are 3 tags
    for (var i=0; i<tags.length; i++) {
        var loopStep = i;
        rawTagData   = [];

        // The return statement
        return GetTweetVolFactory.returnTweetVol(url+tags[i].term_id)
            .success(function(data, status, headers, config) {
                rawTagData.push(data);

                // One the last loop, call formatTagData
                // which fills the tweetArrayObjsContainer Array
                if (loopStep === (rawTagData.length - 1)) {
                    formatTagData(rawTagData);
                    deferred.resolve();
                    return deferred.promise;
                }
            });
    }

    function formatTagData(rawData) {

        for (var i=0; i<rawData.length; i++) {
            var data_array = [];
            var loopNum = i;

            for (var j=0; j<rawData[loopNum].frequency_counts.length; j++) {
                var data_obj = {};
                data_obj.x = rawData[loopNum].frequency_counts[j].start_epoch;
                data_obj.y = rawData[loopNum].frequency_counts[j].tweets;
                data_array.push(data_obj);
            }

            var tweetArrayObj = {
                "key" : "Quantity"+(loopNum+1), "type" : "area", "yAxis" : 1, "values" : data_array
            };

            tweetArrayObjsContainer.push(tweetArrayObj);
        }
    }
}

इस रेखा का ध्यान रखें

return GetTweetVolFactory.returnTweetVol(url+tags[i].term_id)

यह मेरे लूप के अंदर है:

for (var i=0; i<tags.length; i++)

सब कुछ बहुत अच्छा काम करता है अगर मुझे केवल एक बार के माध्यम से लूप करना पड़ता है हालांकि जैसे ही कोई और टैग (3 तक) है, तब भी यह केवल पहले लूप / डेटा देता है यह तब तक इंतजार नहीं करता जब तक लूप नहीं किया जाता। फिर वादा वापस दो। इसलिए मेरा tweetArrayObjsContainer हमेशा केवल पहला टैग tweetArrayObjsContainer


तीन मुद्दों:

  1. आपने getTagQuotes विधि से आस्थगित वादे को वापस नहीं किया।
  2. आप देख रहे थे कि क्या आप पाश के माध्यम से थे, और लूप के लिए पहले से ही पूरा हो चुका है ( i == (tags.length - 1) )
  3. आपने लूप की पहली यात्रा में return को कहा था ताकि आप दूसरे आइटम पर नहीं पहुंच सकें।

यहां सही कोड है (अभी तक इसका परीक्षण नहीं किया गया)

function getTagQuotes(tags) {
    var deferred = $q.defer(); // setting the defer
    var url      = 'app/api/social/twitter/volume/';
    var tagsComplete = 0;

    for (var i=0; i<tags.length; i++) {
        rawTagData   = [];
        GetTweetVolFactory.returnTweetVol(url+tags[i].term_id)
            .success(function(data, status, headers, config) {
                rawTagData.push(data);
                tagsComplete++;

                if (tagsComplete === tags.length) {
                    formatTagData(rawTagData);
                    deferred.resolve();
                }
            });
    }

    return deferred.promise;
}

इस प्रश्न के संदर्भ में और पहले प्रश्न :

  • सामान्य में कोड सरणी के साथ बहुत क्लीनर होगा। मैप () कई जगहों पर छोरों के बदले में।
  • getTagQuotes() को वायदे की एक सरणी बनाकर क्लीनर बनाया जाएगा, उसे $q.all() जमा कर और एक कुल वादा वापस कर दिया जाएगा
  • formatTagData() , और उसके कॉलर के साथ इसका संबंध, परिवर्तित rawData वापस करके क्लीनर बनाया जाएगा।

कुछ मान्यताओं के साथ, कोड को इस तरह से कुछ सरल करना चाहिए:

getTagQuotes(tags).then(function(tweetArrayObjsContainer) {
    chartObj.chartData = chartObj.chartData.concat(tweetArrayObjsContainer); // concat() ...
    // chartObj.chartData = tweetArrayObjsContainer;                         // ... or simply assign??
    chartDirective = ScopeFactory.getScope('chart');
    chartDirective.nvd3.drawChart(chartObj.chartData);
});

function getTagQuotes(tags) {
    var url = 'app/api/social/twitter/volume/';
    var promises = tags.map(function(tag) {
        var deferred = $q.defer();
        GetTweetVolFactory.returnTweetVol(url + tag.term_id)
        .success(function(data, status, headers, config) {
            deferred.resolve(data);
        })
        .error(function(data, status) {
            console.log(tag.term_id + ': error in returning tweet data');
            deferred.resolve(null); // resolve() here effectively catches the error
        });
        return deferred.promise;
    });
    return $q.all(promises).then(formatTagData); //this is much much cleaner than building an explicit data array and resolving an outer deferred.

    function formatTagData(rawData) {
        return rawData.filter(function(data) {
            return data || false; // filter out any nulls
        }).map(function(item, i) {
            return {
                'key': 'Quantity' + (i+1),
                'type': 'area',
                'yAxis': 1,
                'color': tagColorArray[i],
                'values': item.frequency_counts.reverse().map(function(c) {
                    return {
                        x: addZeroes(c.start_epoch),
                        y: c.tweets,
                    };
                })
            };
        });
    }
}

आपको यहां दिए गए वादों की एक सरणी वापस करनी चाहिए, जिसका मतलब है कि आपको getTagsQuotes इस तरह से बदलना चाहिए:

function getTagQuotes(tags) {

    var url      = 'app/api/social/twitter/volume/',
        promises = [];

    for (var i=0; i<tags.length; i++) {

       promises.push( GetTweetVolFactory.returnTweetVol( url+tags[i].term_id ) );

    }

    return promises;
}

और फिर इस तरह के वादे के माध्यम से पाश:

if (tags.length > 0) {

    var promises = getTagQuotes(tags);

    promises.map( function( promise ) {

         promise.then( function( data ) { 

            //Manipulate data here

         });

    });
}

संपादित करें: यदि आप चाहते हैं कि सभी वादों को समाप्त करने के लिए टिप्पणी में बताया जाए तो आपको यह करना चाहिए:

if (tags.length > 0) {

    Promise.all( getTagQuotes(tags) ).then( function( data ) { 

        //Manipulate data here

    });
}

संपादित करें : पूर्ण डेटा हेरफेर:

Promise.all( getTagQuotes(tags) ).then( function( allData ) {

allData.map( function( data, dataIndex ){

    var rawData = data.data,
        dataLength = rawData.frequency_counts.length,
        j = 0,
        tweetArrayObj = {
            // "key"    : "Quantity"+(i+1),
            // "color"  : tagColorArray[i],
            "key"    : "Quantity",
            "type"   : "area",
            "yAxis"  : 1,
            "values" : []
        };

    for ( j; j < dataLength; j++ ) {

        rawData.frequency_counts[j].start_epoch = addZeroes( rawData.frequency_counts[j].start_epoch );

        tweetArrayObj.values.push( { x:rawData.frequency_counts[j].start_epoch, y:rawData.frequency_counts[j].tweets  } );

    }

    tweetArrayObjsContainer.push( tweetArrayObj );

});

for ( var i= 0,length = tweetArrayObjsContainer.length; i < length; i++ ) {

    chartObj.chartData.push( tweetArrayObjsContainer[ i ] );

}

chartDirective = ScopeFactory.getScope('chart');
chartDirective.nvd3.drawChart(chartObj.chartData);

});

return deferred.promise; आपके फ़ंक्शन का रिटर्न वैल्यू होना चाहिए, GetTweetVolFactory.returnTweetVol() , क्योंकि यह वह है जो आप का ऐलान करने का इरादा है

आपकी समस्या यह है कि आप कई GetTweetVolFactory.returnTweetVol() को बुला रहे हैं, और फिर आपको अपने वादे के समाधान के लिए उन सभी GetTweetVolFactory.returnTweetVol() कॉल को मर्ज करने की आवश्यकता है। ऐसा करने के लिए, आपको केवल एक GetTweetVolFactory.returnTweetVol() कॉल का GetTweetVolFactory.returnTweetVol() देना चाहिए:

function promisifiedTweetVol(rawTagData, urlStuff) {
    var deferred = $q.defer(); // setting the defer

    GetTweetVolFactory.returnTweetVol(urlStuff)
        .success(function(data, status, headers, config) {
            rawTagData.push(data);

            // One the last loop, call formatTagData
            // which fills the tweetArrayObjsContainer Array
            if (loopStep === (rawTagData.length - 1)) {
                formatTagData(rawTagData);
                deferred.resolve();
            }
        });

    return deferred.promise;
}

और फिर प्रत्येक वादे को एक पाश में बुलाओ और वादा पूरा करें, जो सभी वादे पूरा होने पर हल हो जाएंगे:

function getTagQuotes(tags) {
    var url      = 'app/api/social/twitter/volume/';
    var promises = [];

    // My for loop, which only returns ONCE, even if there are 3 tags
    for (var i=0; i<tags.length; i++) {
        var loopStep = if;
        rawTagData   = [];

        promises.push( promisifiedTweetVol(rawTagData, url+tags[i].term_id) );
    }

    // ...

    return $.when(promises);
}

आपके कोड के साथ कुछ और समस्याएं हैं, लेकिन आपको यह मेरी टिप के साथ काम करने में सक्षम होना चाहिए।


एक सरणी में हर वादे रखो तो करते हैं:

$q.all(arrayOfPromises).then(function(){
  // this runs when every promise is resolved.
});