2017-11-16 54 views
7

एक एसिंक कॉल है जो मैं सेवा पर किसी डेटाबेस पर क्वेरी कर रहा हूं, लेकिन इस सेवा की एक सीमा है कि यह कितनी बार आउटपुट कर सकती है, इसलिए मुझे यह जांचने की ज़रूरत है कि क्या यह परिणाम भेजता है और दोहराता है क्वेरी जब तक यह नहीं करता है।लूप के अंदर async फ़ंक्शंस का पदानुक्रम कॉल करें?

तुल्यकालिक mockup:

var query_results = []; 

var limit_hit = true; #While this is true means that the query hit the record limit 
var start_from = 0; #Pagination parameter 

while (limit_hit) { 
    Server.Query(params={start_from : start_from}, callback=function(result){ 
     limit_hit = result.limit_hit; 
     start_from = result.results.length; 
     query_result.push(result.results); 
    } 
} 

जाहिर है ऊपर काम नहीं करता, मैं इस मुद्दे के बारे में कुछ अन्य प्रश्न यहाँ देखा है, लेकिन वे जब आप प्रत्येक यात्रा की जरूरत के लिए इंतजार करना क्या करना है का उल्लेख नहीं है आखिरी वाला खत्म करने के लिए और आप हाथ से पहले पुनरावृत्तियों की संख्या नहीं जानते हैं।

मैं उपरोक्त एसिंक्रोनस कैसे बदल सकता हूं? मैं वादे/स्थगित-जैसे तर्क का उपयोग करके जवाब देने के लिए खुला हूं, लेकिन अधिमानतः कुछ साफ है।

मैं शायद प्रतीक्षा/टाइमआउट का उपयोग करके ऐसा करने का एक भयानक और भयानक तरीका सोच सकता हूं, लेकिन इसे हल करने के लिए एक साफ, चालाक और आधुनिक तरीका होना चाहिए।

एक और तरीका हाथ से पहले सुविधाओं की संख्या जानने के लिए "पूर्व-क्वेरी" बनाना है ताकि आप लूप की संख्या जान सकें, मुझे यकीन नहीं है कि यह सही तरीका है या नहीं।

यहाँ हम डोजो कभी कभी उपयोग करें, लेकिन उदाहरण मैंने पाया कि क्या करना है की व्याख्या नहीं करता है जब आप छोरों https://www.sitepen.com/blog/2015/06/10/dojo-faq-how-can-i-sequence-asynchronous-operations/

+0

लूप के बजाय एक पुनरावर्ती दृष्टिकोण का उपयोग करें। यह वादे के साथ स्वाभाविक रूप से बह जाएगा। – Bergi

उत्तर

3

की एक अज्ञात मात्रा में आप एक पाश का उपयोग करने के तो मैं वहाँ लगता चाहते हैं नहीं (साफ है) वादे के बिना इसे करने का तरीका।

एक अलग दृष्टिकोण निम्नलिखित होगा:

var query_results = []; 
 

 
var start_from = 0; 
 

 
funciton myCallback(result) { 
 
    if(!result) { 
 
    //first call 
 
    Server.Query({ start_from: start_from}, myCallback); 
 
    } else { 
 
    //repeated call 
 
    start_from = result.results.length 
 
    query_result.push(result.results); 
 
    
 
    if(!result.limit_hit) { 
 
     //limit has not been hit yet 
 
     //repeat the query with new start value 
 
     Server.Query({ start_from: start_from}, myCallback); 
 
    } else { 
 
     //call some callback function here 
 
    } 
 
    } 
 
} 
 

 
myCallback(null);

आप इस पुनरावर्ती कह सकते हैं, लेकिन जब से क्वेरी अतुल्यकालिक है आप कॉल स्टैक सीमा आदि

साथ समस्या नहीं होनी चाहिए

ईएस 6 पर्यावरण में वादे का उपयोग करके आप एसिंक/प्रतीक्षा का उपयोग कर सकते हैं। मुझे यकीन नहीं है कि यह डोजो के साथ संभव है।

+0

यदि यह साफ है, तो मैं वादा के लिए खुला हूं, जहां तक ​​मुझे पता है कि – Mojimi

+0

और मैं आपके उदाहरण को समझ गया हूं, लेकिन जब यह सही हो गया है, तो मुझे कोई तरीका नहीं है? – Mojimi

+0

मैंने सोचा कि यह तब हुआ जब परिणाम.hit_limit सच है? क्या मैंने कुछ गलत समझा? – Lukilas

-1

आप इस POC के लिए प्राप्त करने के लिए एक जनरेटर समारोह Generators उपयोग कर सकते हैं:

कुछ मूल बातें - आप एक asterick * के साथ एक जनरेटर को परिभाषित - यह एक अगले समारोह जो अगले मूल्य रिटर्न को उजागर करता है - जनरेटर कर सकते हैं आंतरिक रूप से उपज बयान से रोक सकते हैं और फोन करके बाहर से शुरू कर सकते हैं next() - (सही) यह सुनिश्चित करते हैं कि जनरेटर नहीं किया जाता है जब तक limit

function *limitQueries() { 
    let limit_hit = false; 
    let start_from = 0; 
    const query_result = []; 

    while (true) { 
    if (limit_hit) {break;} 
    yield Server.Query(params={start_from : start_from}, 
     callback=function* (result) { 
     limit_hit = result.limit_hit; 
     start_from = result.results.length; 
     yield query_result.push(result.results); 
    } 
    } 
} 
तक पहुँच गया है

तो जाहिर है, जेनरेटर फ़ंक्शन अपने राज्य को बनाए रखता है। जेनरेटर समारोह दो गुण { value, done } को उजागर करता है और आप इसे इस

const gen = limitQueries(); 
let results = []; 
let next = gen.next(); 

while(next.done) { 
    next = gen.next(); 
} 
results = next.value; 

आप जनरेटर कॉलबैक को संभालने के लिए अपने Server.Query विधि को छूने के लिए हो सकता है की तरह कह सकते हैं। उम्मीद है की यह मदद करेगा! चीयर्स!

+1

नहीं दिखाने के लिए संपादित किया है, आपको जेनरेटर का उपयोग नहीं करना चाहिए जब आप वास्तव में 'async'/'await' चाहते हैं। आपका कोड बिल्कुल भी काम नहीं करता है - आप तुरंत सबकुछ उपभोग करते हैं, यह एक अनंत लूप में जाता है क्योंकि आप कभी भी 'limit_hit' को असाइन नहीं करते हैं, और मैं यह भी नहीं बता सकता कि वह वैश्विक' कॉलबैक 'चर क्या करना है। – Bergi

2

जब तक आप रेट लिमिटर या कतार लिख नहीं लेते हैं तब तक आप कॉलबैक नहीं समझते हैं;) चाल काउंटर का उपयोग करना है: एसिंक अनुरोध से पहले काउंटर बढ़ाएं, और प्रतिक्रिया मिलने पर इसे कम करें, तो आपको पता चलेगा "उड़ान में" कितने अनुरोध हैं।

यदि सर्वर दबाया गया है तो आप आइटम को कतार में वापस रखना चाहते हैं।

ऐसी कई चीजें हैं जिन्हें आपको ध्यान में रखना होगा: प्रक्रिया की हत्या होने पर कतार का क्या होगा? कोई अन्य अनुरोध भेजने से पहले कितना इंतजार करना है? सुनिश्चित करें कि कॉलबैक कई बार नहीं कहा जाता है! आपको कितनी बार पुनः प्रयास करना चाहिए? छोड़ने से पहले कितना इंतजार करना है? सुनिश्चित करें कि कोई ढीला सिरों नहीं हैं! (कॉलबैक कभी नहीं कहा जाता है)

जब सभी किनारे के मामलों को ध्यान में रखा जाता है तो आपके पास एक लंबा और इतना सुरुचिपूर्ण समाधान नहीं होगा। लेकिन आप इसे एक समारोह में अमूर्त कर सकते हैं! (जो एक वादा करता है या जो भी आप कल्पना करते हैं)। यदि आपके पास कोई उपयोगकर्ता इंटरफ़ेस है तो आप लोडिंग बार और कुछ आंकड़े भी दिखाना चाहते हैं!

4

हालांकि कई उत्तर पहले से ही हैं, फिर भी मुझे विश्वास है कि async/await सबसे साफ तरीका है।

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

और आप कोलाहल

https://babeljs.io/

जे एस async तर्क वाक्य रचना तो async/await को promise को callback से बदल आवश्यकता हो सकती है, वे सब एक ही बात करते हैं, जब callback एक बहुत हम जरूरत घोंसले एक श्रृंखला की तरह कुछ, फिर वादा आते हैं, जब promise लूप में जाता है, तो हमें चेन को और अधिक सरल बनाने की आवश्यकता होती है, फिर async/await आते हैं। लेकिन सभी ब्राउज़र नए सिंटैक्स का समर्थन नहीं करते हैं, इसलिए babel पुराने वाक्यविन्यास में नए वाक्यविन्यास को संकलित करने के लिए आते हैं, तो आप हमेशा नए वाक्यविन्यास में कोड कर सकते हैं।

getData().then((data) => { 
 
    //do something with final data 
 
}) 
 

 
async function getData() { 
 
    var query_results = []; 
 

 
    var limit_hit = true; 
 
    var start_from = 0; 
 
    
 
    //when you use await, handle error with try/catch 
 
    try { 
 
    while (limit_hit) { 
 
     const result = await loadPage(start_from) 
 
     limit_hit = result.limit_hit; 
 
     start_from = result.results.length; 
 
     query_result.push(result.results); 
 
    } 
 
    } catch (e) { 
 
    //when loadPage rejects 
 
    console.log(e) 
 
    return null 
 
    } 
 
    return query_result 
 
} 
 

 
async function loadPage(start_from) { 
 
    //when you use promise, handle error with reject 
 
    return new Promise((resolve, reject) => Server.Query({ 
 
    start_from 
 
    }, (result, err) => { 
 
    //error reject 
 
    if (err) { 
 
     reject(err) 
 
     return 
 
    } 
 
    resolve(result) 
 
    })) 
 
}

+0

वाह जो बहुत अलग है, मैं इसे देख लूंगा और समझने की कोशिश करूंगा, धन्यवाद! – Mojimi

+0

क्या आप अपने उदाहरण में जोड़ सकते हैं जहां मैं हमेशा/विफलता कॉलबैक डालता हूं? – Mojimi

+0

@Mojimi त्रुटि संभाल कोड जोड़ा गया –

0

आप सर्वर प्रतिक्रिया के हर बार का इंतजार करना होगा। यहां एक encapsulated विधि

var query = (function(){ 
    var results = []; 
    var count = 0; 
    return function check(fun){ 
    Server.Query({ start_from: count}, function(d){ 
     count = d.results.length; 
     results.push(d.results); 
     if (d.limit_hit && fun) fun(results); 
     else check(fun); 
    }); 
    }; 
})(); 

// Call here 
var my_query = query(function(d){ 
    // --> retrive all data when limit_hit is true) 
}); 
संबंधित मुद्दे