2015-06-07 7 views
6

के लिए प्रतीक्षा कर रहे हैं मैंने कुछ समय पहले सी # में एक सी दुभाषिया बनाया था और अब इसे जावास्क्रिप्ट में परिवर्तित करना शुरू कर दिया है। सब कुछ ठीक हो रहा था जब तक मुझे एहसास नहीं हुआ कि जेएस में कोई नींद नहीं है। मेरा दुभाषिया एक पुनरावर्ती पार्सर का उपयोग करता है और यह उपयोगकर्ता इनपुट के लिए रुक जाता है, जबकि यह कई कार्यों को गहरा कर देता है (सी # में मैंने दूसरे थ्रेड में वाइंडंडल का उपयोग किया)। मैंने setInterval और setTimeout को देखा है लेकिन वे असीमित/गैर-अवरोधक हैं; बेशक एक व्यस्त चालक सवाल से बाहर है और मैंने एसओ पर पाया गया एक timed_queue कार्यान्वयन देखा लेकिन कोई किस्मत नहीं। मैंने मुख्य विंडो और वेबवर्कर में पार्सर की कोशिश की है। मैं jQuery का उपयोग कर रहा हूँ। मेरे पास जेएस के साथ सीमित अनुभव है और मैं आगे बढ़ने के लिए विचारों की तलाश में हूं। मैं निरंतरता गुजरने वाली शैली, या उपज के बारे में बहुत कुछ जानता हूं और सोच रहा हूं कि क्या वे कुंजी पकड़ सकते हैं। यहां कुछ नियंत्रण सूची दिखाने के लिए कोड से थोड़ा सा कटौती दी गई है। कोई भी विचार करें ...जावास्क्रिप्ट नेस्टेड लूप उपयोगकर्ता इनपुट

var STATE = { 
    START: "START", 
    RUN: "RUN", //take continuous steps at waitTime delay 
    STEP: "STEP", //take 1 step 
    PAUSE: "PAUSE",//wait for next step command 
    STOP: "STOP", 
    ERROR: "ERROR" 
} 
var state = state.STOP; 

function parsing_process() //long process we may want to pause or wait in 
{ 
    while(token !== end_of_file)// 
    { 
     //do lots of stuff - much of it recursive 
     //the call to getNextToken will be encountered a lot in the recursion 
     getNextToken(); 
     if (state === STATE.STOP) 
      break; 
    } 
} 

function getNextToken() 
{ 
    //retrieve next token from lexer array 
    if (token === end_of_line) 
    { 
     //tell the gui to highlight the current line 
     if (state === STATE.STOP) 
      return; 
     if (state === STATE.STEP)//wait for next step 
     { 
      //mimick wait for user input by using annoying alert 
      alert("click me to continue") 
     } 

     if (state === STATE.RUN) { 
      //a delay here - set by a slider in the window 
      //a busy wait haults processing of the window 
     } 
    } 
} 

मैं इस मिल गया है फ़ायरफ़ॉक्स में काम करने के लिए task.js

<html> 
<head> 
    <title>task.js examples: sleep</title> 
    <script type="application/javascript" src="task.js"></script> 
</head> 
<body> 
    Only works in FIREFOX 
    <button onclick="step()">Step</button> 
    <button onclick="run()">Run</button> 
    <button onclick="stop()">Stop</button> 
    <pre style="border: solid 1px black; width: 300px; height: 200px;" id="out"> 
</pre> 

    <script type="application/javascript;version=1.8"> 

     function start() { 
      process(); 
     } 

     function step() { 
      if (state === STATE.STOP) 
       start(); 
      state = STATE.STEP; 
     } 
     function run() { 
      if (state === STATE.STOP) 
       start(); 
      state = STATE.RUN; 
     } 
     function stop() { 
      state = STATE.STOP; 
     } 

     var STATE = { 
      START: "START", 
      RUN: "RUN", //take continuous steps at sleepTime delay 
      STEP: "STEP", //take 1 step 
      PAUSE: "PAUSE",//wait for next step command 
      STOP: "STOP", 
      ERROR: "ERROR" 
     } 

     var state = STATE.STOP; 
     var sleepTime = 500; 

     function process() { 
      var { spawn, choose, sleep } = task; 
      var out = document.getElementById("out"); 
      var i=0; 
      out.innerHTML = "i="+i; 
      var sp = spawn(function() { 
       while(state !== STATE.STOP) 
       { 
        i++; 
        out.innerHTML = "i="+i; 
        if (state === STATE.RUN) 
        { 
         yield sleep(sleepTime); 
        } 
        if (state === STATE.STEP) 
         state = STATE.PAUSE; 
        while (state===STATE.PAUSE) 
        { 
         yield; 
        } 
       } 
      }); 
     } 
    </script> 
</body> 
</html> 

का उपयोग कर मैं इसे सराहना करते हैं अगर कोई है जो वादे के बारे में कुछ पता था कि मुझे कुछ और सुराग दे सकता है। मेरा आवेदन उपभोक्ता नहीं है लेकिन यह अच्छा होगा अगर यह फ़ायरफ़ॉक्स

+1

* पर्यावरण * क्या आप चल रहे हैं? 'नींद' समारोह की अनुपस्थिति मुख्य रूप से एक * पर्यावरण * चीज है, न कि भाषा की बात है। –

+0

आपको वादे का उपयोग करना चाहिए। – SLaks

+0

क्या आप समझा सकते हैं कि इसका उपयोग कैसे किया जा सकता है, यानी, उद्देश्य क्या है? – Roberto

उत्तर

1

JSCPP के लेखक के रूप में, मुझे एक ही समस्या का सामना करना पड़ा जब मैं एक डीबगर लागू कर रहा था जो फ्लाई पर व्याख्या करने वाले कार्यक्रम को रोकता और जारी रखता है। अंत में मैं ईएस 6 से जेनरेटर फ़ंक्शंस का उपयोग करने का निर्णय लेता हूं लेकिन मैं यहां अपनी विचार प्रक्रिया साझा करना चाहता हूं।

सामान्य तरीका निम्न स्तर के रिकर्सिव-मुक्त बाइट-कोड में लक्ष्य कोड संकलित करना है। आप प्रत्येक कथन को लेबल करते हैं और फिर unconditional jump और conditional jump के साथ सभी नियंत्रण प्रवाह को संभालते हैं। फिर आप उस पर एक बाइट-कोड दुभाषिया चलाते हैं। यह एक अच्छा विकल्प है यदि आप इन सभी संकलित कामों को पूरा नहीं करते हैं।

दूसरा तरीका "कॉल स्टैक सेव/कॉल स्टैक लोड" कार्य प्रवाह है। जब आपको व्याख्या करने की रोकथाम की आवश्यकता होती है, तो आप सभी तर्कों और सभी स्थानीय चरों को एक कस्टमाइज्ड स्टैक पर सभी तरह से नीचे की तरफ धक्का देते हैं। जब आपको निष्पादन जारी रखने की आवश्यकता होती है, तो आप इन सभी तर्कों और स्थानीय चरों को दोबारा लोड करते हैं। आपका कोड

AddExpression.prototype.visit = function(param) { 
    var leftVal = visit(this.left, param); 
    var rightVal = visit(this.right, param); 
    return leftVal + rightVal; 
} 

से

AddExpression.prototype.visit = function(param) { 
    if (needToStop) { 
     stack.push({ 
      method: AddExpression.prototype.visit, 
      _this: this, 
      params: [param], 
      locals: {}, 
      step: 0 
     }); 
     return; 
    } 
    if (recoverFromStop && stack.top().step === 0) { 
     var thisCall = stack.pop(); 
     if (stack.length > 0) { 
      var nextCall = stack.top(); 
      nextCall.method.apply(nextCall._this, params); 
     } 
    } 
    var leftvalue = visit(this.left, param); 
    if (needToStop) { 
     stack.push({ 
      method: AddExpression.prototype.visit, 
      _this: this, 
      params: [], 
      locals: { 
       leftvalue: leftvalue 
      }, 
      step: 1 
     }); 
     return; 
    } 
    if (recoverFromStop && stack.top().step === 1) { 
     var thisCall = stack.pop(); 
     leftvalue = thisCall.locals.leftvalue; 
     if (stack.length > 0) { 
      var nextCall = stack.top(); 
      nextCall.method.apply(nextCall._this, params); 
     } 
    } 
    var rightvalue = visit(this.right, param); 
    if (needToStop) { 
     stack.push({ 
      method: AddExpression.prototype.visit, 
      _this: this, 
      params: [], 
      locals: { 
       leftvalue: leftvalue, 
       rightvalue: rightvalue 
      }, 
      step: 2 
     }); 
     return; 
    } 
    if (recoverFromStop && stack.top().step === 2) { 
     var thisCall = stack.pop(); 
     leftvalue = thisCall.locals.leftvalue; 
     rightvalue = thisCall.locals.rightvalue; 
     if (stack.length > 0) { 
      var nextCall = stack.top(); 
      nextCall.method.apply(nextCall._this, params); 
     } 
    } 
    return leftvalue + rightvalue; 
}; 

इस विधि के लिए परिवर्तित हो जाएगा अपने दुभाषिया का मुख्य तर्क को नहीं बदलता है, लेकिन आप अपने आप के लिए देख सकते हैं कि पागल कोड एक सरल ए + बी वाक्य रचना के लिए है ।

अंत में मैं जेनरेटर का उपयोग करने का निर्णय लेता हूं। जेनरेटर प्रोग्राम निष्पादन को अंतःक्रियात्मक रूप से बदलने के लिए नहीं बल्कि आलसी मूल्यांकन के उद्देश्य के लिए हैं। लेकिन कुछ सरल हैकिंग के साथ, हम "जारी रखें" आदेश प्राप्त करने पर आलसी-मूल्यांकन हमारे बयानों का उपयोग कर सकते हैं।

function interpret(mainNode, param) { 
    var step; 
    var gen = visit(mainNode); 
    do { 
     step = gen.next(); 
    } while(!step.done); 
    return step.value; 
} 

function visit*(node, param) { 
    return (yield* node.visit(param)); 
} 

AddExpression.prototype.visit = function*(param) { 
    var leftvalue = yield* visit(this.left, param); 
    var rightvalue = yield* visit(this.right, param); 
    return leftvalue + rightvalue; 
} 

यहाँ, function* दर्शाता है कि हमने AddExpression.visit समारोह जनरेटर समारोह होना चाहता हूँ। yield*visit कॉल के बाद visit फ़ंक्शन स्वयं एक पुनरावर्ती जनरेटर फ़ंक्शन है।

यह समाधान पहली नज़र में बिल्कुल सही लगता है लेकिन यह जनरेटर (http://jsperf.com/generator-performance) का उपयोग करके एक विशाल प्रदर्शन में कमी से पीड़ित है और यह es6 से है और कई ब्राउज़र इसका समर्थन नहीं करते हैं।

निष्कर्ष के लिए, आपको व्यवधान कारक निष्पादन को प्राप्त करने के तीन अलग-अलग तरीके होते हैं:

  1. निम्न स्तर के कोड को संकलित:
    • सकारात्मक: आम बात, चिंताओं में से अलग, अनुकूलन करने के लिए आसान है और बनाए रखने के
    • विपक्ष: बहुत ज्यादा काम
  2. बचाने के ढेर/लोड ढेर:
    • सकारात्मक: अपेक्षाकृत तेज, तर्क की व्याख्या रखती
    • विपक्ष: कठिन बनाए रखने के लिए
  3. जनरेटर:
    • सकारात्मक: बनाए रखने के लिए आसान है, पूरी तरह से तर्क
    • विपक्ष: धीमी, es6 को es5 को पार करने की आवश्यकता है
2

से अधिक में चलाया गया है यदि आप ब्राउज़र में अपनी स्क्रिप्ट चला रहे हैं और उपयोगकर्ता के इनपुट की प्रतीक्षा करनी है (ईवेंट, फील्ड-चेंज इवेंट इत्यादि पर क्लिक करें)) - तब आप ब्राउज़र के ईवेंट की प्रतीक्षा करने के लिए "while" और "रोकें" का उपयोग नहीं कर सकते हैं। इवेंट हैंडलर को असीमित रूप से बुलाया जाएगा, और उस समय तक "लूप" टोकन की एक सूची पढ़ना भी समाप्त कर सकता है। शायद आपको टोकन द्वारा टोकन पढ़ने और इसके मूल्य पर आधारित करने का प्रयास करना चाहिए - अगली कार्रवाई को कॉल करें।

इस उदाहरण का प्रयास करें: http://jsbin.com/puniquduqa/1/edit?js,console,output

1

काम यहाँ https://github.com/felixhao28/JSCPP किया बहुत उपयोगी है, वह जनरेटर का उपयोग करता है और यह Chrome और Firefox दोनों में चलता है।

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