环境检测:node.js或浏览器 [英] Environment detection: node.js or browser

查看:204
本文介绍了环境检测:node.js或浏览器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个需要在客户端和服务器端工作的JS应用程序(在浏览器和Node.js中的Javascript),我想能够重用



我发现窗口是一个只能在浏览器上访问的变量,和全局,因此我可以检测代码在哪个环境中执行(假设没有脚本声明窗口变量)



它们是两个问题。


  1. 检测代码在哪个浏览器中运行。例如,此代码是否正确。 (这段代码是inline的,意思是它被一些全局代码包围,在两个环境中重用)

     如果窗口? 
    totalPath =../examples/#{path}
    else
    totalPath =../../examples/#{path}


  2. 如何在这两个环境中使用全局变量?现在,我做了以下,但这真的不舒服。

     如果窗口? 
    window.DocUtils = {}
    window.docX = []
    window.docXData = []
    else
    global.DocUtils = {}
    global .docX = []
    global.docXData = []



<注意:这个问题有两个部分,但因为标题是环境检测:node.js或浏览器 - 我将首先访问此部分,因为我想很多人都来这里寻找答案。单独的问题可能是按顺序的。



在JavaScript变量中可以由内部作用域重新定义,因此假设环境没有创建名为process的变量,全局或窗口可能很容易失败,例如,如果使用node.js jsdom模块, API使用示例

  var window = doc.defaultView; 

之后,根据窗口变量将由在该范围下运行的任何模块系统地失败。使用相同的逻辑,任何基于浏览器的代码都很容易覆盖全局进程,因为它们不是该环境中的保留变量。



幸运的是,有一种方法需要全局范围并测试它是什么 - 如果你使用 new Function()创建一个新函数, 构造函数,的执行范围绑定到全局范围,您可以将全局范围直接与预期值进行比较。 *)



所以要创建一个函数检查全局作用域是否是window将是

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

//测试全局作用域是否绑定到窗口
if(isBrowser())console.log(running under browser);

并且用于测试全局sope是否绑定到global的函数将是

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

//测试全局作用域是否绑定到global
if(isNode())console.log(running under node.js);

try ... catch -part将确保如果变量未定义, false



isNode()也可以比较 this.process.title === node或者在node.js中找到的一些其他全局作用域变量,如果你愿意的话,但是在实践中与全局比较应该足够了。



http://jsfiddle.net/p6yedbqk/



:不建议检测运行环境。但是,在具有全局范围的某些已知特征的开发和测试环境等特定环境中,它可能很有用。



在环境检测完成后,您可以选择要使用哪种基于环境的策略(如果有)将您的变量绑定到您的应用程序。



在我看来,推荐的策略是使用单例模式来绑定类中的设置。在SO中已有一个很好的选择列表



最简单/最清晰的方式在JavaScript中实现单例?



因此,如果你不需要全局变量,并且根本不需要环境检测,只需使用单例模式定义一个模块,该模块将为您存储值。好的,可以认为模块本身是一个全局变量,在JavaScript中它实际上是,但至少在理论上看起来有点干净的做法。



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


注意:使用Function构造函数创建的函数不会为其创建上下文创建
闭包;它们总是在
全局范围中创建。当运行它们时,他们只能访问
自己的局部变量和全局变量,而不能访问
中调用了Function构造函数的变量。



I'm developping a JS-app that needs to work both on the client side and the server side (in Javascript on a browser and in Node.js), and I would like to be able to reuse the parts of the code that are used for both sides.

I have found out that window was a variable only accessible on Browsers, and global in node, so I can detect in which environment the code is executing (assuming that no script declares the window variable)

They are two problems.

  1. How should I detect in which browser the code is running. For example, is this code OK. (This code is inline, meaning that it is surrounded by some global code, reused for both environments)

    if window?
        totalPath= "../examples/#{path}"
    else
        totalPath= "../../examples/#{path}"
    

  2. How can I use global variables for both environments ? Now, I'm doing the following, but this really doesn't feel right.

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

解决方案

NOTE: This question had two parts, but because the title was "Environment detection: node.js or browser" - I will get to this part first, because I guess many people are coming here to look for an answer to that. A separate question might be in order.

In JavaScript variables can be redefined by the inner scopes, thus assuming that environment has not created variables named as process, global or window could easily fail, for example if one is using node.js jsdom module, the API usage example has

var window = doc.defaultView;

After which detecting the environment based on the existence of window variable would systematically fail by any module running under that scope. With the same logic any browser based code could easily overwrite global or process, because they are not reserved variables in that environment.

Fortunately there is a way of requiring the global scope and testing what it is - if you create a new function using a new Function() constructor, the execution scope of this is binded to the global scope and you can compare the global scope directly to the expected value. *)

So to create a function check if the global scope is "window" would be

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

And function to test if global sope is binded to "global" would be

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 will makes sure that if variable is not defined, false is returned.

The isNode()could also compare this.process.title==="node" or some other global scope variable found inside node.js if you will, but comparing to the global should be enough in practice.

http://jsfiddle.net/p6yedbqk/

NOTE: detecting the running environment is not recommended. However, it can be useful in a specifiic environment, like development and testing environment which has some known characteristics for the global scope.

Now - the second part of the answer. after the environment detection has been done, you can select which environment based strategy you want to use (if any) to bind your variable which are "global" to your application.

The recommended strategy here, in my opinion, would be to use a singleton pattern to bind your settings inside a class. There is a good list of alternatives already in SO

Simplest/Cleanest way to implement singleton in JavaScript?

So, it may turn out if you do not need a "global" variable, and you do not need the environment detection at all, just use the singleton pattern to defined a module, which will store the values for you. Ok, one can argue that the module itself is a global variable, which in JavaScript it actually is, but at least in theory it looks a bit cleaner way of doing it.

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

Note: Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was called.

这篇关于环境检测:node.js或浏览器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆