Подтвердить что ты не робот

Обнаружение среды: node.js или браузер

Я разрабатываю JS-приложение, которое должно работать как на стороне клиента, так и на стороне сервера (в Javascript в браузере и в Node.js), и я хотел бы иметь возможность повторно использовать компоненты кода, который используется для обеих сторон.

Я обнаружил, что window была переменной, доступной только в браузерах, и global в node, поэтому я могу определить, в какой среде выполняется код (при условии, что no script объявляет window variable)

Это две проблемы.

  • Как определить, в каком браузере работает код. Например, это код ОК. (Этот код является встроенным, что означает, что он окружен некоторым глобальным кодом, повторно используемым для обеих сред)

    if window?
        totalPath= "../examples/#{path}"
    else
        totalPath= "../../examples/#{path}"
    
  • Как использовать глобальные переменные для обеих сред? Теперь я делаю следующее, но это действительно не так.

    if window?
        window.DocUtils = {}
        window.docX = []
        window.docXData= []
    else
        global.DocUtils= {}
        global.docX = []
        global.docXData = []
    
4b9b3361

Ответ 1

ПРИМЕЧАНИЕ. Этот вопрос состоял из двух частей, но поскольку название было "Обнаружение среды: node.js или браузер" - я сначала займусь этой частью, потому что, по-моему, многие люди приходят сюда, чтобы найти ответ к тому, что. Отдельный вопрос может быть в порядке.

В переменных JavaScript могут быть переопределены внутренние области, поэтому, предполагая, что среда не создала переменные, называемые процессом, глобальные или окна могут легко завершиться неудачей, например, если вы используете модуль node.js jsdom, Пример использования API

var window = doc.defaultView;

После чего обнаружение среды, основанной на существовании переменной window, будет систематически отказываться от любого модуля, работающего под этой областью. С той же логикой любой код на основе браузера может легко перезаписать global или process, поскольку они не являются зарезервированными переменными в этой среде.

К счастью, существует способ потребовать глобальную область и проверить, что это такое - если вы создаете новую функцию с помощью конструктора new Function(), область выполнения this привязана к глобальной области, и вы можете сравнить глобальный охват непосредственно к ожидаемому значению. *)

Итак, чтобы создать функцию, проверьте, будет ли глобальная область "окном"

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");

И функция, чтобы проверить, привязана ли глобальная привязка к глобальному, будет

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");

попытка... catch -part убедится, что если переменная не определена, возвращается false.

isNode() также может сравнить this.process.title==="node" или некоторую другую глобальную переменную области видимости внутри node.js, если вы это сделаете, но по сравнению с глобальным должно быть достаточно на практике.

http://jsfiddle.net/p6yedbqk/

ПРИМЕЧАНИЕ: определение рабочей среды не рекомендуется. Однако он может быть полезен в конкретной среде, такой как среда разработки и тестирования, которая имеет некоторые известные характеристики для глобальной области.

Теперь - вторая часть ответа. после обнаружения среды, вы можете выбрать, какую стратегию на основе среды вы хотите использовать (если есть), чтобы привязать переменную, которая является глобальной "к вашему приложению.

Рекомендуемая стратегия здесь, на мой взгляд, заключалась бы в использовании шаблона singleton для привязки ваших настроек внутри класса. В SO

есть хороший список альтернатив,

Простейший/Самый чистый способ реализовать singleton в JavaScript?

Итак, может получиться, если вам не нужна "глобальная" переменная, и вам вообще не требуется обнаружение среды, просто используйте шаблон singleton для определения модуля, который сохранит значения для вас. Хорошо, можно утверждать, что сам модуль является глобальной переменной, которая на самом деле в JavaScript, но по крайней мере теоретически это выглядит немного более чистым способом.

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

Примечание. Функции, созданные с помощью конструктора Function, не создают закрытие их контекстов создания; они всегда создаются в глобальный охват. При их запуске они смогут получить доступ их собственные локальные переменные и глобальные, а не те из них в котором был вызван конструктор Function.

Ответ 2

Так как очевидно, что Node.js может иметь как (w/NW.js?), мой индивидуальный способ сделать это, обнаружив, что элемент node существует в объекте process.versions.

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

Многоуровневые условия - избегать ошибок при поиске в переменной undefined из-за некоторых ограничений браузеров.

Ссылка: https://nodejs.org/api/process.html#process_process_versions

Ответ 3

Вы можете подключиться к переменному окну или глобальному - в зависимости от ситуации. Хотя это не рекомендуется для создания многоплатформенного приложения JS:

var app = window ? window : global;

Гораздо лучше иметь свою глобальную переменную, которая будет использоваться по логике приложения, но будет состоять из частей на основе разных платформ. Что-то вроде:

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

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

Итак, идея состоит в том, что ваша основная логика приложения будет абсолютно одинаковой и будет использовать один и тот же объект, только глобальный объект должен быть изменен на основе среды. Это делает ваше приложение более переносимым и гибким с точки зрения платформ.

Ответ 4

Для этого есть пакет npm, который можно использовать как на стороне клиента, так и на стороне сервера.

браузера или узел-

Вы можете использовать его таким образом

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

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

Отказ от ответственности: я являюсь автором этого пакета :)

Ответ 5

Я знаю, что это поздний ответ на вопрос (1,5 года), но почему бы не скопировать jQuery исходный код?

if (typeof module === "object" && typeof module.exports === "object") {
  // node
}

if (typeof window !== "undefined" && typeof window.document !== "undefined") {
  // browser
}

Удачи.