2013-07-10 13 views
28

Opracowuję aplikację JS, która musi działać zarówno po stronie klienta, jak i po stronie serwera (w JavaScript w przeglądarce i w Node.js), a ja chciałbym być w stanie ponownie wykorzystać części kodu, które są używane dla obu stron.Wykrywanie środowiska: node.js lub przeglądarka

I odkryli, że window była zmienna dostępna tylko w przeglądarkach i global w węźle, więc mogę wykryć w którym środowisko kod jest wykonywany (zakładając, że żaden skrypt deklaruje zmienną window)

Są dwa problemy.

  1. Jak należy wykryć w którym przeglądarka działa kod. Na przykład, czy ten kod jest OK. (Ten kod jest inline, co oznacza, że ​​jest otoczony przez jakiegoś globalnego kodu, ponownie wykorzystane zarówno dla środowisk)

    if window? 
        totalPath= "../examples/#{path}" 
    else 
        totalPath= "../../examples/#{path}" 
    
  2. Jak mogę używać zmiennych globalnych dla obu środowiskach? Teraz robię co następuje, ale to naprawdę nie jest w porządku.

    if window? 
        window.DocUtils = {} 
        window.docX = [] 
        window.docXData= [] 
    else 
        global.DocUtils= {} 
        global.docX = [] 
        global.docXData = [] 
    
+0

Możliwy duplikat [Jak sprawdzić, czy skrypt jest uruchomiony w węźle .js?] (https://stackoverflow.com/questions/4224606/how-to-check-whether-a-script-is-running-under-node-js) –

Odpowiedz

47

UWAGA: To pytanie składa się z dwóch części, ale ponieważ tytuł brzmiał "Wykrywanie środowiska: node.js lub przeglądarka" - najpierw przejdę do tej części, ponieważ myślę, że wiele osób przychodzi tutaj, by szukać odpowiedzi do tego. Oddzielne pytanie może być w porządku.

W zmiennych JavaScript może zostać na nowo przez wewnętrzne zakresach, a więc przy założeniu, że środowisko nie stworzył zmiennych nazwanych jako proces, globalne lub okno może łatwo zawieść, na przykład jeśli ktoś jest za pomocą modułu node.js jsdom The API usage example has

var window = doc.defaultView; 

Po czym wykrycie środowiska w oparciu o istnienie zmiennej window zakończy się systematycznie niepowodzeniem przez dowolny moduł działający pod tym kątem. Przy tej samej logice każdy kod oparty na przeglądarce mógłby z łatwością nadpisać global lub process, ponieważ nie są one zmiennymi zarezerwowanymi w tym środowisku.

Na szczęście istnieje sposób wymagający zasięg globalny i testowania, co to jest - jeśli utworzyć nową funkcję używając new Function() konstruktor zakres wykonanie this jest oprawiony w zakresie globalnym i można porównać zasięg globalny bezpośrednio do oczekiwanej wartości.*)

więc stworzyć kontrolę działania, jeżeli zakres globalny to "okno" byłoby

var isBrowser=new Function("try {return this===window;}catch(e){ return false;}"); 

// tests if global scope is binded to window 
if(isBrowser()) console.log("running under browser"); 

i funkcja aby sprawdzić, czy globalny SopE jest binded do "globalne" byłoby

var isNode=new Function("try {return this===global;}catch(e){return false;}"); 

// tests if global scope is binded to "global" 
if(isNode()) console.log("running under node.js"); 

the try ... catch -part upewni się, że jeśli zmienna nie zostanie zdefiniowana, zwracana jest nazwa false.

Można także porównać this.process.title==="node" lub inną zmienną zakresu globalnego znajdującą się w pliku node.js, ale w porównaniu do wersji globalnej powinno wystarczyć.

http://jsfiddle.net/p6yedbqk/

UWAGA: wykrywanie środowiska bieg nie jest zalecane. Może to jednak być przydatne w specyficznym środowisku, takim jak środowisko programistyczne i testowe, które ma pewne znane cechy globalnego zasięgu.

Teraz - druga część odpowiedzi. po wykryciu środowiska, możesz wybrać strategię opartą na środowisku, której chcesz użyć (jeśli jest), aby powiązać zmienną, która jest "globalna" dla twojej aplikacji.

Zalecana strategia tutaj, moim zdaniem, polegałaby na użyciu pojedynczego wzoru do wiązania ustawień wewnątrz klasy. Nie jest dobrym lista alternatyw już w takim

Simplest/Cleanest way to implement singleton in JavaScript?

więc może okazać się, jeśli nie potrzebujemy zmiennej „globalne” i nie trzeba wykrywania środowiska w ogóle, po prostu użyć wzór singleton do zdefiniowanego modułu, który zapisze wartości dla ciebie. Ok, można argumentować, że sam moduł jest zmienną globalną, która w języku JavaScript tak naprawdę jest, ale przynajmniej teoretycznie wygląda to nieco czystszy sposób robienia tego.

*) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

Uwaga: Funkcje utworzone z konstruktora Function nie tworzą zamknięć do ich kontekstach stworzenia; są zawsze tworzone w globalnym zasięgu . Podczas ich uruchamiania będą mogły uzyskać dostęp tylko do własnych zmiennych lokalnych i globalnych, a nie do tych z zakresu , w których wywołano konstruktor funkcji.

+1

cześć, dzięki za dostarczenie tego rozwiązania, próbowałem wielu rzeczy, ale ten działał idealnie, więc opublikowałem pakiet npm z tym, mam nadzieję, że nie masz nic przeciwko temu ... sprawdź to https : //www.npmjs.com/package/detect-is-node – abhirathore2006

+0

@ abhirathore2006 bardzo minimalistyczny;) może nadal być jednym liniowcem, module.exports = (nowa funkcja ("try {return this === global;} catch (e) {return false;} "))(); –

+0

tak, zgadzam się, ale jeśli chcesz go użyć 100 razy, łatwiejsze stanie się czytanie i zrozumienie prostej funkcji. – abhirathore2006

8

można dołączyć do okna lub zmienna globalna - na podstawie sytuacji. Choć nie jest to zalecany sposób dokonywania wieloplatformowa aplikacja JS:

var app = window ? window : global; 

Jest o wiele lepiej mieć swoją globalną zmienną, która będzie używana przez logikę aplikacji, ale zostaną wykonane z elementów o podstawie różne platformy. Coś jak:

var app = { 
    env: '', 
    agent: '' 
}; 

if (window) { 
    app.env = 'browser'; 
    app.agent = navigator.userAgent; 
} else if (process) { 
    app.env = 'node'; 
} 

Więc chodzi o to, że głównym logika aplikacji będzie absolutnie takie same i będą używać tego samego obiektu, tylko że globalny obiekt musiał zostać zmieniony na podstawie środowiska. Dzięki temu twoja aplikacja jest znacznie bardziej przenośna i elastyczna pod względem platform.

+0

Dzięki, znalazłem inny wpis, który jest obsługiwany część coffeescript http://stackoverflow.com/questions/4214731/coffeescript-global-var iables, więc to jest wspaniałe – edi9999

9

Ponieważ najwyraźniej node.js może mieć zarówno (w/NW.js?), Mój osobisty sposób to zrobić to poprzez wykrywanie jeśli wpis node istnieje process.versions obiektu.

var isNode = false;  
if (typeof process === 'object') { 
    if (typeof process.versions === 'object') { 
    if (typeof process.versions.node !== 'undefined') { 
     isNode = true; 
    } 
    } 
} 

Wielopoziomowość warunków polega na unikaniu błędów podczas przeszukiwania niezdefiniowanej zmiennej ze względu na ograniczenia niektórych przeglądarek.

referencyjny: https://nodejs.org/api/process.html#process_process_versions

1

Jest pakiet npm właśnie do tego i może być stosowany zarówno na stronie klienta i po stronie serwera.

browser-or-node

można go używać w ten sposób

if (isBrowser) { 
    // do browser only stuff 
} 

if (isNode) { 
    // do node.js only stuff 
} 

Oświadczenie: ja jestem autorem tego pakietu :)

+0

Zastrzeżenie: jesteś niesamowity! –

Powiązane problemy