Could the following code ever throw an error?
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("somethingwrong");
In chromium, it does just return null.
How would it be if the the requested rendering context is known to a browser? (Like "webgl" or "experimental-webgl") Is there the possibility of an error exception? In chromium I could not provoke this behavior.
In other words: Do I need to wrap this code in a try/catch in a library that checks cleanly for a rendering context?
Is there maybe a way to objectify this? E.g. by a web service that tries a code snipped in different browsers and lists their possibly differing results.
Returning null is the expected behavior if the requested context is not available, or if the canvas has already been assigned to a different type of context:
Returns null if the given context ID is not supported, if the canvas
has already been initialized with the other context type (e.g. trying
to get a "2d" context after getting a "webgl" context).
There are special cases where an exception can be thrown related to proxy scenarios (ibid):
Throws an InvalidStateError exception if the setContext() or
transferControlToProxy() methods have been used.
In addition to that, even though a browser may support a certain type of context there is no guarantee that the object can be created if the system resources such as memory are low in which case null would be returned.
Here is an overview of what will be returned in different (common) scenarios.
So unless you are using proxy transfers (which is not exactly widely supported at this time) you do not need to use try-catch with getContext().
Tip: in the future canvas will get a property probablySupportsContext() which can be used before getContext(). This will do these tests and return false if conditions are not met (supported context, already in use with different context type, low resources etc.):
var supported = canvas . probablySupportsContext(contextId [, ... ] )
Returns false if calling getContext() with the same arguments would
definitely return null, and true otherwise.
Update Just wanted to elaborate on a special case - for vendor specific extensions it is in theory possible to get an exception thrown depending on that very specific extension and how it defines its behavior. But these are and should not be considered part of the standard and since they are experimental in most cases, a risk and non-standard behavior is implied.
Related
The global methods setInterval and setTimeout are different between browser (window) and NodeJS (global). The behavior is quite the same. Both doing the same.
See docs about NodeJS and Browser. In Node the returned value is a instance of a Timeout class. The browsers methods returns just a number, a handler id.
How to work with this difference if you developing for browsers but testing with Node, because test-framework engine is node (e.g. Jest). Do I need to switch to a browser test-engine?
(btw) Also, in my case I restrict all global variables. So I have to access only by the scope name. e.g. window.setInterval or global.setInterval not just setInterval. (It's a tslint rule no-restricted-globals)
Anyway there is a type conflict between Node's and browser's timer functions.
Is there a good practice to handle it? Do I have to switch my test-engine? But finally they doing the same. Maybe I have to cast to any-type?
I know this is not a JavaScript specification. It's the enviroment dependency. I do not say that they should be exactly the same. I'm just wondering how to deal with it when I run unit tests on node-js but I'm developing for browser. Currently only the return values are different. The behavior itself seems to be equal.
The Nashorn Javascript engine (part of Java 8) reports some exceptions, esp. regarding method binding errors like arity or type mismatches, as a NativeTypeError-instance, which does not have a cause relation to get any exception and is therefore very opaque to me (I'd like to report as much as possible back to the script user).
Is there a documented method to get root causes or further information from a NativeTypeError-instance?
ECMAScript standard only defines name and message properties on Error objects like TypeError, ReferenceError etc.
Nashorn defines certain extension properties such as "lineNumber", "columnNumber", "fileName" (for the source where exception was thrown from) and "stack" to access stack trace. Also "printStackTrace", "getStackTrace" functions are supported via Error.prototype extensions.
See also:
https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-ExtensionsofErrorobjects,Error.prototypeandErrorconstructor
Answering my own question: the semantics of NativeTypeError are described in the ECMAScript standard (ECMA-262, sec. 15.11.7). Instances of NativeTypeError expose a public field message, which is of type Object, but is most likely a String for all circumstances I've encountered it.
I have a webgl page running in chrome.
Every now and then chrome will report the following error.
[.WebGLRenderingContext]GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to render with no buffer attached to enabled attribute 1
I've tried to debug where the error is occurring but I cannot. I can reliably cause it to occur, but when I debug the error is reported on seemingly random lines. I suspect this is because of the asynchronous nature of gpu rendering.
Is there a good way to debug this?
You can use a debug wrapper to wrap the WebGL context and call gl.getError after every WebGL function.
There is an example of one available on the official WebGL Wiki.
Per default WebGL doesn't tell you much about it, you have to query all the information you need yourself. Once you know how to do that, those errors will tell you all you need to debug it. The getter for your case would be
var attribLocation = 1;
gl.getVertexAttrib ( attribLocation, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING );
Which, if you query it before your draw call, will probably return null, which means you're not calling vertexAttribPointer correctly when setting up or switching buffers.
So you go to the point in your code where you set the pointers and enable the arrays and confirm that the location you just enabled with enableVertexAttribArray returns also returns null if you query the buffer at this point. Now you know if you messed up with the pointer. You know you fixed it, when the query returns the correct WebGLBuffer Object.
There are getters for all the states (WebGL is mostly about managing state), they are a bit tricky to use, but using them will greatly help you understand everything going on all the time, when you need or don't need to make calls in order to update that state and where you made mistakes.
You can look the getters and the arguments they take up in the spec
SpectorJS is a tool aimed at WebGl developers wanting to know what happens in their context. It enables capturing of all the available information from a frame. You will be able to look at your entire commands list with their associated visual states and context information.
https://github.com/BabylonJS/Spector.js
ESMA 262 5.1 for many Array.prototype functions say that they are intentionally generic and described in terms of [[Get]], [[Put]], etc operations on Object, but also require length property.
So them allowed to work on build-in objects, like:
obj = {"a":true, "length":10};
Array.prototype.push.call(obj, -1);
console.log(obj); // Object { 10: -1, a: true, length: 11 }
For native objects standard have note:
Whether the push function can be applied successfully
to a host object is implementation-dependent.
Is arguments host object? Seems that all DOM (as NodeList) are host objects. And them work in modern browsers.
MDN docs warn about < IE9. What about another browsers? What about nodejs native objects? What about Rhino/Nashorn native objects?
UPDATE #jfriend00 Hm, I didn't think about [[Put]] operation... In ECMA 5.1 I found special notes about such situation:
Host objects may implement these internal methods in any manner
unless specified otherwise; for example, one possibility is that
[[Get]] and [[Put]] for a particular host object indeed fetch and
store property values but [[HasProperty]] always generates false.
However, if any specified manipulation of a host object's
internal properties is not supported by an implementation, that
manipulation must throw a TypeError exception when attempted.
So in bad case you get TypeError!
Since you never really got a complete answer, I'll take a stab at answering some of the questions you posted.
Is arguments host object?
arguments is part of the Javascript language, not a host object. It has a pretty well defined behavior which has been modified some when running in strict mode. Since arguments does not persist beyond the current function call (not even in a closure) and since it is not meant to be mutable, the usual way of handling the arguments object is to immediately make a copy into a real array where you can then use all the normal array methods on it and it can persist in a closure to be accessed by a local function.
MDN docs warn about < IE9. What about another browsers?
It's not very specific to generalize here about a particular browser. Instead, you'd have to examine a specific object and then specific versions of a browser. Older versions of IE did have a reputation for having host objects that didn't interoperate as well with Javsacript (in this way), but you'd really have to examine a specific object to know what you could and couldn't do.
What about nodejs native objects?
node.js is much more pure Javascript environment than the browser because there is no DOM, no window object, etc... Did you have any specific node.js objects in mind that you wanted to ask about? In my somewhat limited experience with node.js, I'm just seeing actual JS objects, though there are many places that node.js interfaces with the OS so perhaps there are some non JS objects in those interfaces (I haven't encountered any yet, but that is a possibility).
So in bad case you get TypeError!
As I said in my comments, using any array object that attempts to modify the array such as .splice() is very likely to cause problems with host objects as many host objects are not meant to be modified directly. Plus reading the specification and assuming that older browsers all follow the specification (without extensive testing to verify that) can be dangerous. In particular, older versions of IE are famous for not following the specification. So, again, you can't just assume you would get a TypeError without proper testing.
If you're looking for a general purpose safe way to code, one will never go wrong by copying an array-like host object into an actual array and then using array operations on the actual array. That's guaranteed to be safe. There's a cross-browser polyfill for Array.prototype.slice that works with all browsers for copying into an actual array on the MDN page for .slice(). If you're only supporting IE 9 and up, you don't need the polyfill.
And, one should never assume that any operation that changes the array-like object is generally safe on a host object (there could be specific exceptions, but you'd have to do a lot of testing to be sure). My preference is to write code that I know will be safe and does not require a lot of testing to guarantee that. Copying into an actual array gives me that every time.
If you want to be sure it will work, better convert it to an array first.
To convert an array-like object to an array, you can use ES6 Array.from. Currently only Firefox 32 supports it, but there is a polyfill.
Alternatively, [].slice.call(arrayLike) will work on most browsers.
According to this MDN page, the delete keyword
Returns false only if the property exists and cannot be deleted. It
returns true in all other cases.
However, I see cases where delete returns true, despite the property not being deleted:
delete Window
delete alert
delete dir
delete console
delete 2
delete null
delete {}.x
...
In fact, almost all properties of window return true with delete, as can be seen by the running the following script in about:blank:
for(a in window) { if(delete window[a]) { console.log(a); } }
However, most properties of window do not actually get deleted. What is the true meaning of the returned value of delete? Why does it return true for properties it doesn't delete?
(Note: I would be interested in references to Chromium code explaining the behaviour of delete.)
The window is a host object, one whose semantics are defined by the host environment, e.g. the browser. delete when applied to properties of host objects is more complicated than when applied to native objects.
Host objects may support these internal properties with any implementation-dependent behaviour as long as it is consistent with the specific host object restrictions stated in this document.
Section 11.4.1 - The delete operator says
If IsUnresolvableReference(ref) then,
If IsStrictReference(ref) is true, throw a SyntaxError exception.
Else, return true.
so when a host object doesn't support deletion or modification of a property, then it returns an unresolvable reference or a reference which pretends to be deleted. Either approach causes true to be returned in non-strict mode.
The javascript implementation used by browsers has always been bending the rules. Part of the javascript DOM API is not even possible in pure javascript, for instance the dom innerHTML="something" that triggers an event. This was fixed in EcmaScript5, but you can't rely on the Browser Object Model being 100% legit javascript. AFAIK, as long as you don't put a foot into the DOM and the BOM, you can rely completly on the ecmascript standard.
Given that you are acting on low level objects in your program, the attributes may in fact be being deleted and then immediately re-added, though I have no idea how you could test for this behavior.
On that MDN page, it specifies the syntax, which does not include delete object as your first set of examples uses. It does specify the syntax delete object[property] as your second example shows. However, what happens with DOM (host) objects is not specified. See this article for more information.
Basically, the browsers are protecting the runtime environment of the browser, in your test.
Once upon a time, that might not have been the case, but as far as tests go, this is akin to asking why Windows doesn't allow you to open the command-shell and run:
> cd /
> deltree *.*
anymore.
Because there is really no good reason to be able to do such a thing, when you're expecting the environment to actually continue to run, afterwards, and not take down your whole browser, plus potentially the instance of your OS you're currently running, or whatever other fun errors could occur when you basically ask a program to erase itself in real-time, while it currently has low-level access to your GPU/soundcard/input devices.
Delete will return failure in the case where you try to delete a var. In terms of global properties the browser needs to function, most of them are defined like a property (ie: window.location) but are done so at a low-level (ie: you don't have access). So theoretically, they're objects which can be deleted. But they're protected, so you can't, but that's not going to change the return statement of delete, because that would alter delete's expected behaviour.
So:
function () {
var obj = { prop : true };
delete obj; /* fail */
delete object.prop; /* succeed */
}