PHP rocks! wünscht allen Mitgliedern einen guten Rutsch ins neue Jahr 2017 !!!
Hinweis: Das Forum zieht um! Um keine Datenverluste zu haben, schalten wir zwecks Übernahme der Daten das Forum am Sonntag, den 24.04.2016 um ca. 21:00 Uhr offline und passen anschliessend die DNS-Einträge an.
www.php-rocks.de wird euch dann nach den Aktualisierungen der DNS-Server wieder wie gewohnt uneingeschränkt zur Verfügung stehen.
Danke für euer Verständnis!

Themabewertung:
  • 0 Bewertung(en) - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Migrate async+syncronous require to only async
#1
Hallo,
ich habe mir die require Funktion und mein library so schön node.js like nachgebaut und die shims runtergeladen, so daß node.js scripts in der Regel im Browser funktionieren ( sogar require('fs') = FilesystemAPI/indexedDB ).
Und alles funktioniet eigentlich wunderbar, eigentlich bin ich ehrlich gesagt einwenig stolz auf mich.

Aber:
Synchrone XMLHttpRequest ist zukunft nur noch im worker erlaubt wie jeder weiß.
Meine nachgebaute require Funktion mit Cache und module context(zumteil in arbeit) unterstützt sync und oder async, je nachdem ob eine callback Funktion übergeben wird.

Ich habe auch eine vm/shim require('vm') und habe vor demnächst die module in den vm context zu schicken (ich errinere an meine frdl language Cool )

Nun gib es die eine Möglichkeit, die synchronen require calls solange in den Promise zu schicken bis er resolved wird, was aber den Prozess anhalten würde und einfrieren könnte.
Die andere Möglichkeit wäre mehr "sexy": Einen Worker zu starten, die files vorher von der VM nach dem "initial require" zu parsen/etc und die requires in den cache zu laden und das modul erst auszuführen wenn die required module im cache sind, dann nämlich funktioniert im folgenden auch das synchrone require.

Any more suggestions? Kann jemand was dazu sagen? Wißt Ihr was ich meine?

Heart Ich liebe Euch Alle, fast alle Big Grin

mfg
Till
Antworten
#2
Ich konnte mein Vorhaben realisieren, ich habe BEIDE obigen Ansätze verwendet (Parsing/Compile+Preload, und Promise+Generator)!


Zunächst parse ich die auflösbaren(*) require calls welche left-hand assigned sind, also wenn der vorherige Token ein "=" oder ein "return" ist. Die anderen Aufrufe der require Funktion verwenden mutmaßlich eine callbackfunktion als Argument und sind somit in der Laufzeit asynchron und benötigen keine Behandlung.
(*) Mit "Auflösbar" ist gemeint, der identifier/url/modulename ist ein String (ohne vars, etc) und wird NICHT zur Laufzeit geformt.

Mein library ermöglicht zusätzlich asynchrone requires, und require calls in asynchronen Funktionen/zur Laufzeit, im Gegenssatz zu node.js, in node.js werden die imports mit dem file geladen und die requires sollten möglichst am Anfang stehen/synchron sein. Hierzu siehe weiter unten...
Code:
var _javascriptCompiler = function(js, module) {
                            function p(mod) {
                                var m = ('undefined' !== typeof mod.parent) ? mod.parent : mod || frdl.main;
                                return m;
                            }
                            
                            
                            function url_rewrite_1(url){
                                //if('undefined'==typeof require.cache('url'))return url;
                                //var __U =  require.cache('url');
                                var __U = require('url');
                                
                                var m = p(module);
                                var U = __U.parse(m.descriptor.location.url);
                                var u = U.resolve(url);
                                var s = (3 === parseInt(m.descriptor.location.server)) ? 5 : m.descriptor.location.server;
                                u = s + ':' + u;
                                if (false === strpos(U.path, '.')) u += '.js';        
                                return u;                    
                            }
                      
                             function url_rewrite_2(url){
                                return url;    
                             }
                            
                            

                            var _require = ('undefined' !== typeof module && 'undefined' !== typeof module.require) ? module.require : require;
                            
                            
                                             
              var urlMatchingRegex = /require\(["']([\.]{1,2}\/[^"']*)["'][\)\,]/gi;
                            js = js.replace(urlMatchingRegex, function(fullMatch, url) {
                                var u = url_rewrite_1(url);
                                var fm = frdl.str_replace(url, u, fullMatch);
                                return fm;
                            });
                                  
            
                          
                            
                            
                            var lit = frdl.clone(frdl.lit);
                            lit.opts.identify_number_literals = true;
                            lit.opts.identify_simple_literals = false;
                            lit.opts.overlook_html_comment_markers = false;
                            
                            var ast = lit.lex(js);
                            
                            var i = 0, t = false, tok = false, Toks = [];                            
                           //  var _regex = /([^\n\,;!?\s{}=]+)/i;
                             var _regex = /([^\n\,;!?\s{}]+)/i;
                            
                            var requiredUrls = [], reqUrl = false, req = false;
                            
                            for(i=0; i < ast.length-1; i++){
                              Toks = [];
                              tok  =ast[i];
                              if(0===tok.type){
                                  t = tok.val.split(_regex);
                                  frdl.each(t, function(i, t){
                                      if(''!==t && ' ' !== t)Toks.push(t);    
                                });

                                if('require(' === Toks[Toks.length-1]){
                                      if(2===ast[i+1].type){
                                        reqUrl = ast[i+1].val.substr(1,ast[i+1].val.length-2);
                                        
                                                                            
                                        if(')'===ast[i+2].val.substr(0,1) || ','===ast[i+2].val.substr(0,1) ){
                                            req = {
                                               returnTok : Toks[Toks.length-2],
                                               url : reqUrl
                                            };
                                            
                                            requiredUrls.push(req);
                                        }
                                        
                                     }
                                }
                              }    
                            }
                            
                            
                          function preload_requires(){
                            frdl.each(requiredUrls, function(i, req){
                                
                                
                                  function loadAsText(){
                                        _require(url_rewrite_2(req.url), function(){
                                          
                                         }, require.getCompiler('plain/text'), 'plain/text');                              
                                  }                                    

                                
                                
                                if('=' === req.returnTok){
                                    
                                       _require(url_rewrite_2(req.url), function(){
                                          
                                      });
                                      
                                      loadAsText();
                                      
                                }else if('return' === req.returnTok /* && false === !!frdl.main */){
                                
                                       if( 'undefined' === typeof frdl.main){
                                           webfan.$Async(function(){                     
                                              _require(url_rewrite_2(req.url), function(){
                                          
                                               });
                                           },1);
                                      }else{
                                            webfan.$Async(function(){       
                                             _require(url_rewrite_2(req.url), function(){
                                          
                                               });
                                            },1);    
                                       }    
                                      
                                           loadAsText();      
                            
                                }
                            });
                          }    
                          
                            
                          if( false === !!frdl.main){
                                preload_requires();
                          }else{
                                preload_requires();
                          }
                        
                          
                          
                            var js_preload_cache = '';
                              /*  
                              frdl.each(requiredUrls, function(i, req){
                                if('=' === req.returnTok){
                                  js_preload_cache+="require('"+req.url+"', function(){});";
                                }else if('return' === req.returnTok){
                                  js_preload_cache+="require('"+req.url+"', function(){});";
                                }
                              });    
                              */     
                              
                              
                            js_preload_cache+="(function(){(function(){return; }());return; }());";
                          
                          
                           js = lit.generate(ast);
                          
                      
        

                            
                           return 'if(\'undefined\'===typeof __filename && module && module.sourceURL){' + 'var __filename = module.sourceURL;'
                           + '}' + 'if(\'undefined\'===typeof ___filename){'
                           + 'var ___filename = __filename;'
                           + '}' + 'if(\'undefined\'===typeof __dirname && __DIR__){'
                           + 'var __dirname = __DIR__;' + '}'
                           + 'if(\'undefined\'===typeof __FILE__ && __DIR__){' + 'var __FILE__ = __filename;' + '}'
                           + '(' + 'function(exports, require, module, frdl, webfan, __filename, __dirname, __FILE__, __DIR__, Widget){'
                           + '\r\n'
                           + js_preload_cache
                           + '\r\n'
                           + js
                           + '\r\n'
                            + 'return exports;' + '\r\n' + '\r\n}'
                            + '(exports, require, module, frdl, webfan, __filename, __dirname, __FILE__, __DIR__, (\'undefined\'!==typeof Widget) ? Widget : ((\'undefined\'!==typeof module.Widget) ?module.Widget:undefined)));\r\n//# sourceURL='
                             + module.sourceURL;
                        };


Es verbleiben Fälle, welche nach dem obigen System nicht behandelt werden und immer noch synchron sind.
Hier hat mir folgendes geholfen:
Browser welche synchrone XMLHttpRequests NICHT mehr implementieren (z.B. Edge), unterstützen wahrscheinlich schon GeneratorFunctions ( function *() ) und yield.
Mithilfe dessen sollte es möglich sein eine Art "await" zu simulieren.
Hier gibt es ein recht anschauliches Beispiel:
view-source:https://googlesamples.github.io/web-fundamentals/fundamentals/getting-started/primers/async-generators-example.html
view-source:https://googlesamples.github.io/web-fundamentals/fundamentals/getting-started/primers/utils.js
Meine eigene Implementation ist teilwse noch in Arbeit, es sollen auch Browser unterstützt werden welche noch keine Generator Funktionen oder Arrow Functions bieten, syntax rewrite...
https://github.com/frdl/-Flow/blob/master/hist/mobile.make-require-async.js#L11674
https://github.com/frdl/-Flow/blob/master/hist/mobile.make-require-async.js#L11719
Code:
if( 'function'!==typeof callback
                             && 3>opts.recursive_count
                            ){

                                   descriptor.mime = mime;
                                  
                                try{      
                                   module.require(module,function (mod){
                                            // alert('Await -ed for mod: '+mod.toString());
                                   }, compiler, mime, opts);
                                }catch(err){
                                                     console.error('error require frdl.Await.spawn: '+err);
                                                       }            
                                  
                                         
                                
frdl.Await.spawn.call(descriptor, function $___GENERATOR___(){
       "use strict";
                                          
                                          try{
                                             var descriptor = this;
                                             var cacheid = cacheID(descriptor.id + (('string' === typeof descriptor.mime) ? '#' + descriptor.mime : ''));
                                             var prom = new Promise(function(resolve, reject) {
                                                            (function __check(){
                                                             if ('undefined' !== typeof require.cache()[cacheid]) {
                                                                     resolve(require.cache()[cacheid]);
                                                            }else{
                                                                
                                                                webfan.$Async(function(){
                                                                    __check();
                                                                },1);
                                                                
                                                            }    
                                                          
                                                         }());
                                                       });
                                            }catch(err){
                                                  console.error('error require frdl.Await.spawn in Promise: '+err);
                                          }            
                                                      
                                                      
                              
                                                      
                                         var waitFor = $___YIELD___(); frdl.Await.waitForPromise(prom);
                                   });
                                  
  return require.cache()[cacheid];
}
Antworten
#3
Danke fürs posten Deiner Lösung.
Antworten
#4
Hallo Arne,
ja mh, ich denke zwar ich bin auf dem richtigen Weg, aber irgendwie klappt das noch nicht hundertprozentig.
Kann an meinem library liegen ich muß das ganze noch überarbeiten.
Vielleicht hat ja jemand ein ähnliches Problem und kann was dazu beitragen?

mfg
Till
Antworten
#5
Ich kann da leider nichts beitragen, sorry... Blush
Antworten
#6
So es klappt nun.
Allerdings ist die Seite nun bedeutend langsamer: Muß ich noch optimieren:
Im nächsten Schritt will ich sehen inwieweit ich das preloading u.a. in Worker auslagern kann...

Geädert habe ich u.a. im _javascriptCompiler werden nun im preloading nur die required files in den file-cache geladen, also ohne bisher komplett required+compiled+usw... https://github.com/frdl/-Flow/blob/master/hist/dev1.js#L16047

...
mfg
Till
Antworten
#7
Ich bin dabei die alte Version zu "bereinigen".

Hab was gefunden was in etwa meinen Anforderungen entsprechen könnte:
In der nächsten Version werde ich wohl auf requirejs und https://github.com/guybedford/amd-loader zurückgreifen!
Antworten


Gehe zu: