2012-06-07 17 views
6

जबकि IndexedDB की अद्भुत दुनिया के माध्यम से अपने रास्ते बना रही है, मैं मोज़िला टेस्ट स्वीट से this की तरह कोड भर में आया था:बताएं कि इस जावास्क्रिप्ट कोड में इंडेक्सड डीबी के साथ जनरेटर का उपयोग कैसे किया जाता है?

/** 
* Any copyright is dedicated to the Public Domain. 
* http://creativecommons.org/publicdomain/zero/1.0/ 
*/ 

var testGenerator = testSteps(); 

function testSteps() 
{ 
    const IDBObjectStore = Components.interfaces.nsIIDBObjectStore; 
    const name = this.window ? window.location.pathname : "Splendid Test"; 
    const description = "My Test Database"; 

    var data = [ 
    { name: "inline key; key generator", 
     autoIncrement: true, 
     storedObject: {name: "Lincoln"}, 
     keyName: "id", 
     keyValue: undefined, 
    }, 
    { name: "inline key; no key generator", 
     autoIncrement: false, 
     storedObject: {id: 1, name: "Lincoln"}, 
     keyName: "id", 
     keyValue: undefined, 
    }, 
    { name: "out of line key; key generator", 
     autoIncrement: true, 
     storedObject: {name: "Lincoln"}, 
     keyName: undefined, 
     keyValue: undefined, 
    }, 
    { name: "out of line key; no key generator", 
     autoIncrement: false, 
     storedObject: {name: "Lincoln"}, 
     keyName: null, 
     keyValue: 1, 
    } 
    ]; 

    for (let i = 0; i < data.length; i++) { 
    let test = data[i]; 

    let request = mozIndexedDB.open(name, i+1, description); 
    request.onerror = errorHandler; 
    request.onupgradeneeded = grabEventAndContinueHandler; 
    let event = yield; 

    let db = event.target.result; 

    let objectStore = db.createObjectStore(test.name, 
              { keyPath: test.keyName, 
              autoIncrement: test.autoIncrement }); 

    request = objectStore.add(test.storedObject, test.keyValue); 
    request.onerror = errorHandler; 
    request.onsuccess = grabEventAndContinueHandler; 
    event = yield; 

    let id = event.target.result; 
    request = objectStore.get(id); 
    request.onerror = errorHandler; 
    request.onsuccess = grabEventAndContinueHandler; 
    event = yield; 

    // Sanity check! 
    is(test.storedObject.name, event.target.result.name, 
        "The correct object was stored."); 

    request = objectStore.delete(id); 
    request.onerror = errorHandler; 
    request.onsuccess = grabEventAndContinueHandler; 
    event = yield; 

    // Make sure it was removed. 
    request = objectStore.get(id); 
    request.onerror = errorHandler; 
    request.onsuccess = grabEventAndContinueHandler; 
    event = yield; 

    ok(event.target.result === undefined, "Object was deleted"); 
    db.close(); 
    } 

    finishTest(); 
    yield; 
} 

उनके अन्य परीक्षण, एक समान शैली में लिखे गए हैं के रूप में कयामत की ठेठ "पिरामिड करने का विरोध किया "शैली जिसे आप इंडेक्सड डीबी के साथ देखते हैं, एसिंक्रोनस कॉलबैक को एक साथ रखा जा रहा है (और, ज़ाहिर है, जनरेटर फ़ायरफ़ॉक्स से व्यापक रूप से समर्थित नहीं हैं ..)।

तो, मोज़िला से यह कोड कुछ हद तक आकर्षक और दिलचस्प है क्योंकि यह बहुत साफ दिखता है, लेकिन मुझे पूरा यकीन नहीं है कि yield इस संदर्भ में क्या कर रहा है। क्या कोई इसे समझने में मेरी सहायता कर सकता है?

+0

मैं किस तरह का विवरण प्रदान कर सकता हूं? – buley

+0

मुझे पूरी तरह से यकीन नहीं है। मैं अभी भी वास्तव में समझ में नहीं आता कि क्या हो रहा है। संदर्भ के लिए, [यहां वह जगह है जहां grabEventAndContinueHandler परिभाषित किया गया है] (http://hg.mozilla.org/mozilla-central/file/895e12563245/dom/indexedDB/test/helpers.js)। क्या यह किसी भी तरह से कह रहा है "जब आप 'उपज' रेखा पर जाते हैं, तब तक प्रतीक्षा करें जब तक कि ईवेंट समाप्त नहीं हो जाता"? कैसे? – dumbmatter

+0

इसके अलावा, आपके मूल उत्तर और आपके अन्य इंडेक्सड डीबी उत्तरों के लिए धन्यवाद। आप दुनिया के कुछ लोगों में से एक हैं जो वास्तव में इस बारे में लिख रहे हैं कि इसका उपयोग कैसे किया जाना चाहिए, ऐसा लगता है। – dumbmatter

उत्तर

4

यह कोड का एक शानदार टुकड़ा है जो फ़ायरफ़ॉक्स द्वारा खुलासा जावास्क्रिप्ट 1.7 की शक्तिशाली नई विशेषताओं का लाभ उठाता है, और चूंकि इंडेक्सड डीबी केवल फ़ायरफ़ॉक्स और क्रोम द्वारा समर्थित है, मैं कहूंगा कि यह एक उत्कृष्ट व्यापार है।

कोड की पहली पंक्ति फ़ंक्शन testSteps से जनरेटर बनाता है और इसे testGenerator चर से निर्दिष्ट करता है। जेनरेटर का उपयोग करने का कारण यह है क्योंकि इंडेक्सड डीबी पूरी तरह से एसिंक्रोनस एपीआई है; और एसिंक्रोनस प्रोग्रामिंग और नेस्टेड कॉलबैक एक दर्द है। जेनरेटर का उपयोग करके आप इस दर्द को आसानी से सिंक्रोनस लगने वाले एसिंक्रोनस कोड लिखने की अनुमति देते हैं।

नोट: आप को पता है जनरेटर की शक्ति का लाभ उठाने के लिए कैसे अतुल्यकालिक कोड तुल्यकालिक बनाना चाहते हैं following article पढ़ें।

व्याख्या करने के लिए कैसे जनरेटर अतुल्यकालिक प्रोग्रामिंग को सहने लायक निम्नलिखित कोड पर विचार करने के लिए उपयोगी होते हैं:

var name = "Test"; 
var version = 1.0; 
var description = "Test database."; 

var request = mozIndexedDB.open(name, version, description); 

request.onupgradeneeded = function (event) { 
    var db = event.target.result; 

    var objectStore = db.createObjectStore("Thing", { 
     keyPath: "id", 
     autoIncrement: true 
    }); 

    var object = { 
     attributeA: 1, 
     attributeB: 2, 
     attributeC: 3    
    }; 

    var request = objectStore.add(object, "uniqueID"); 

    request.onsuccess = function (event) { 
     var id = event.target.result; 
     if (id === "uniqueID") alert("Object stored."); 
     db.close(); 
    }; 
}; 

ऊपर कोड हम Test नाम के एक डेटाबेस के लिए अनुरोध किया है। हमने डेटाबेस संस्करण 1.0 के लिए अनुरोध किया है। चूंकि यह अस्तित्व में नहीं था onupgradeneeded इवेंट हैंडलर निकाल दिया गया था। एक बार जब हमें डेटाबेस मिला तो हमने उस पर ऑब्जेक्ट स्टोर बनाया, ऑब्जेक्ट स्टोर में ऑब्जेक्ट जोड़ा, और इसे सहेजने के बाद हमने डेटाबेस बंद कर दिया।

उपर्युक्त कोड के साथ समस्या यह है कि हम डेटाबेस के लिए अनुरोध कर रहे हैं और इसके साथ जुड़े अन्य परिचालनों को असीमित रूप से कर रहे हैं। इससे कोड को बनाए रखना बहुत मुश्किल हो सकता है क्योंकि अधिक से अधिक नेस्टेड कॉलबैक नियोजित होते हैं।

इस समस्या को हम जनरेटर का उपयोग इस प्रकार का समाधान करने के लिए:

function grabEventAndContinueHandler(event) { 
    gen.send(event); 
} 

जनरेटर इस प्रकार के रूप में शुरू किया गया है::

var gen = (function (name, version, description) { 
    var request = mozIndexedDB.open(name, version, description); 

    request.onupgradeneeded = grabEventAndContinueHandler; 

    var event = yield; 

    var db = event.target.result; 

    var objectStore = db.createObjectStore("Thing", { 
     keyPath: "id", 
     autoIncrement: true 
    }); 

    var object = { 
     attributeA: 1, 
     attributeB: 2, 
     attributeC: 3 
    }; 

    request = objectStore.add(object, "uniqueID"); 

    request.onsuccess = grabEventAndContinueHandler; 

    event = yield; 

    var id = event.target.result; 

    if (id === "uniqueID") alert("Object stored."); 

    db.close(); 
}("Test", 1.0, "Test database.")); 

grabEventAndContinueHandler समारोह जनरेटर के बाद इस प्रकार परिभाषित किया गया है

gen.next(); 

जनरेटर शुरू होने के बाद एक बार एसी खोलने के लिए अनुरोध किया जाता है दिए गए डेटाबेस के लिए कनेक्शन। फिर grabEventAndContinueHandler एक ईवेंट हैंडलर के रूप में onupgradeneeded ईवेंट में संलग्न है। अंत में हम कीवर्ड yield का उपयोग कर जेनरेटर को उपज या रोक देते हैं।

जनरेटर स्वचालित रूप से फिर से शुरू हो जाता है जब gen.send विधि grabEventAndContinueHandler फ़ंक्शन से कॉल की जाती है। यह फ़ंक्शन बस एक ही तर्क लेता है जिसे event कहा जाता है और इसे जनरेटर को भेजता है। जब जेनरेटर फिर से शुरू किया जाता है तो भेजे गए मान को event नामक चर में संग्रहीत किया जाता है।

संक्षेप में, जादू यहां होता है:

// resume the generator when the event handler is called 
// and send the onsuccess event to the generator 
request.onsuccess = grabEventAndContinueHandler; 

// pause the generator using the yield keyword 
// and save the onsuccess event sent by the handler 
var event = yield; 

ऊपर कोड के रूप में अगर यह तुल्यकालिक थे यह संभव एसिंक्रोनस कोड लिखने के लिए बनाता है। जनरेटर के बारे में और जानने के लिए निम्नलिखित MDN article पढ़ें। उम्मीद है की यह मदद करेगा।

+1

ग्रेट स्पष्टीकरण! इंगित करने के लिए एक बात यह है कि "उपज" वास्तव में निष्पादन "रोक" या "रोक" नहीं देती है। यह बस gen.send() या gen.next() कॉल पर वापस आ जाता है। ठंडा हिस्सा निश्चित रूप से है कि आप gen.send() या gen.next() को दोबारा कॉल करके निष्पादन जारी रखते हैं। यहां तक ​​कि कूलर यह है कि अगर उपज बयान और लूप संरचनाओं के अंदर काम करता है। इससे लूप लिखना आसान हो जाता है जो एक कर्सर पर असीमित रूप से लूप करता है। हालांकि यह देखने के लिए एक बात यह है कि फ़ायरफ़ॉक्स का उपयोग करने वाले वाक्यविन्यास 100% सिंटैक्स से मेल नहीं खाता है जो ईएस 6 मानकीकृत करेगा। हम निश्चित रूप से spec का पालन करने के लिए अद्यतन करेंगे। –

1

grabEventAndContinueHandler() मोज़िला codebase में आईडीबी परीक्षणों में all overthe place अटे पड़े है, लेकिन मैं these की एक जोड़ी से परे एक परिभाषा नहीं मिल सकता है: एक समारोह परिभाषा मैं क्या नहीं कह सकता बिना

function grabEventAndContinueHandler(event) { 
    testGenerator.send(event); 
} 

ऐसा करता है लेकिन मुझे लगता है कि वे टेस्ट सूट का हिस्सा हैं और घटना संदेशों को पास करते हैं क्योंकि ये अन्य लोग करते हैं। yield एक वैश्विक प्रतीत होता है, जो शायद grabEventAndContinueHandler() के अंदर से परीक्षण सूट से परिणाम निकालता है।


मुझे लगता है कि होता है कि यहां yield सिर्फ एक वैश्विक वस्तु createObjectStore, objectStore.add() और objectStore.get आमंत्रण से घटना परिणाम के साथ grabEventAndContinueHandler में सेट हो जाता है कि है।

यदि यह सहायक है, तो मैं रूबी में yield अवधारणा के उपयोग पर आपको कुछ पृष्ठभूमि दूंगा। यह map() जैसा है - यह एक ऐसा कीवर्ड है जो संदेशों को वापस इटरेटर के बाहर कोड के "ब्लॉक" पर भेजता है।

मैं यह नहीं कह सकता कि yield निश्चितता के साथ यहां क्या कर रहा है (यह एक फ़ंक्शन प्रतीत नहीं होता है), लेकिन यहां इंडेक्सड डीबी के मेरे ज्ञान के आधार पर एक शॉट है।

आईडीबी के साथ इस सौदे को देखते हुए, मुझे पता है कि उपज वस्तु में इवेंट ऑब्जेक्ट (let event = yield) है, एक ऑब्जेक्ट जिसमें event.target.result विशेषता है।

के बाद से है कि घटना केवल एक onsuccess कॉलबैक से आता है विशेषता, और यहाँ request.onsuccess = grabEventAndContinueHandler, मुझे लगता है कि कर सकते हैं grabEventAndContinueHandler कोड की "ब्लॉक" के बराबर है और जिसके परिणामस्वरूप घटना वस्तु की स्थापना द्वारा मुख्य थ्रेड के लिए वापस "झुकेंगे" है यह वैश्विक वस्तु।

संबंधित मुद्दे