473,383 Members | 1,868 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

setTimeout(this.doAnimation, 1000) will fail if it is defined in aclass definition

I did some animation using
var oDiv = {};
oDiv.x = 100;
oDiv.y = 100;
oDiv.node = document.getElementById('divImage');
oDiv.node.style.position = "absolute";

oDiv.doAnimation = function() {
oDiv.x += 1;
oDiv.y += 1;
oDiv.node.style.top = oDiv.y + 'px';
oDiv.node.style.left = oDiv.x + 'px';
setTimeout(oDiv.doAnimation, 33);
}
and it works fine. When it is changed to the traditional class
definition, then it fails:
function Animation() {
this.x = ...
etc...

this.doAnimation = function() {
// do something

// set delay
setTimeout(this.doAnimation, 33);
}
}

oDiv = new Animation();
oDiv.doAnimation();
which will fail. The second time when the doAnimation() is called, it
seems that it doesn't have a concept of this.x, etc.

It is the same if I use the more popular way of defining a class by
moving the function out:
function Animation() {
this.x = ...
etc...
}

Animation.prototype.doAnimation = function() {
// do something
}
and it is the same, the second time when doAnimation() is invoked by
the setTimeout, it doesn't have a concept of this.x.

Does someone know what it is? hm... I don't need to use prototype.js
and use something like doAnimation.bind(this) ? Can it be a self-
contained script that doesn't rely on other framework? Thanks.

Oct 4 '08 #1
19 1814
liketofindoutwhy meinte:
and it works fine. When it is changed to the traditional class
definition, then it fails:
There are no classes in JS.
>
function Animation() {
this.x = ...
etc...

this.doAnimation = function() {
// do something

// set delay
setTimeout(this.doAnimation, 33);
}
}

oDiv = new Animation();
oDiv.doAnimation();
which will fail. The second time when the doAnimation() is called, it
seems that it doesn't have a concept of this.x, etc.
[snip]
Does someone know what it is?
You need a closure. Google "javascript closure" and read.

You will eventually end up with something like

var that = this;
....
window.setTimeout(that.doAnimation, 33);

Gregor
--
http://photo.gregorkofler.at ::: Landschafts- und Reisefotografie
http://web.gregorkofler.com ::: meine JS-Spielwiese
http://www.image2d.com ::: Bildagentur für den alpinen Raum
Oct 4 '08 #2
Gregor Kofler wrote:
liketofindoutwhy meinte:
>function Animation() {
this.x = ...
etc...

this.doAnimation = function() {
// do something

// set delay
setTimeout(this.doAnimation, 33);
}
}

oDiv = new Animation();
oDiv.doAnimation();
which will fail. The second time when the doAnimation() is called, it
seems that it doesn't have a concept of this.x, etc.

[snip]
Does someone know what it is?

You need a closure. Google "javascript closure" and read.

You will eventually end up with something like

var that = this;
...
window.setTimeout(that.doAnimation, 33);
Should be

window.setTimeout(function() { that.doAnimation() }, 33);

because with your code the method loses its connection to `that' (being
passed as just another Function object reference) and `this' in its
execution context will again refer to the Window or Global Object instead.
PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Oct 4 '08 #3
Thomas 'PointedEars' Lahn meinte:
Gregor Kofler wrote:
>window.setTimeout(that.doAnimation, 33);

Should be

window.setTimeout(function() { that.doAnimation() }, 33);
Oops. Sorry. My bad. My version does exactly _not_ create a closure.

Gregor
--
http://photo.gregorkofler.at ::: Landschafts- und Reisefotografie
http://web.gregorkofler.com ::: meine JS-Spielwiese
http://www.image2d.com ::: Bildagentur für den alpinen Raum
Oct 4 '08 #4

wow, that's a lot of this and that... and by the way, is it just
Javascript? Do other language automatically say... ok... it is
this.doAnimation, so when I call doAnimation, I will make sure it is
applied on the current object "this" is referring to.
by the way, someone gave me a solution (besides using Prototype.js
setTimeout(this.doAnimation.bind(this), 33);

define a global function:

function bindIt(obj, func) {
return function() { func.apply(obj) }
}

and then use

setTimeout(bindIt(this, this.doAnimation), 33);

Oct 5 '08 #5
On Oct 5, 11:25*pm, liketofindoutwhy <liketofindout...@gmail.com>
wrote:
wow, that's a lot of this and that... *and by the way, is it just
Javascript? *Do other language automatically say... ok... it is
this.doAnimation, so when I call doAnimation, I will make sure it is
applied on the current object "this" is referring to.

by the way, someone gave me a solution (besides using Prototype.js
setTimeout(this.doAnimation.bind(this), 33);

define a global function:

* * * * function bindIt(obj, func) {
* * * * * * return function() { func.apply(obj) }
* * * * }

and then use

setTimeout(bindIt(this, this.doAnimation), 33);
You could as well do:

function Animation () {
var that= this;
this.x = ...
etc...
this.doAnimation = function () {
//use 'that' instead of 'this'
// do something
// set delay
setTimeout(arguments.callee, 33);
};
};

but then doAnimation() is permanently bound to 'that'.

--
Jorge.
Oct 5 '08 #6
liketofindoutwhy wrote:
wow, that's a lot of this and that... and by the way, is it just
Javascript? Do other language automatically say... ok... it is
this.doAnimation, so when I call doAnimation, I will make sure it is
applied on the current object "this" is referring to.
You have failed to phrase an intellible question.
by the way, someone gave me a solution (besides using Prototype.js
setTimeout(this.doAnimation.bind(this), 33);

define a global function:

function bindIt(obj, func) {
return function() { func.apply(obj) }
}

and then use

setTimeout(bindIt(this, this.doAnimation), 33);
That's (Prototype.js) junk, not a solution. To begin with, it requires
Function.prototype.apply() to be supported, or it breaks, needlessly.
PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm>
Oct 6 '08 #7
On Oct 5, 4:16 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
Gregor Kofler wrote:
liketofindoutwhy meinte:
function Animation() {
this.x = ...
etc...
this.doAnimation = function() {
// do something
// set delay
setTimeout(this.doAnimation, 33);
}
}
oDiv = new Animation();
oDiv.doAnimation();
which will fail. The second time when the doAnimation() is called, it
seems that it doesn't have a concept of this.x, etc.
[snip]
Does someone know what it is?
You need a closure. Google "javascript closure" and read.
You will eventually end up with something like
var that = this;
...
window.setTimeout(that.doAnimation, 33);

Should be

window.setTimeout(function() { that.doAnimation() }, 33);

because with your code the method loses its connection to `that' (being
passed as just another Function object reference) and `this' in its
execution context will again refer to the Window or Global Object instead.
I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work? Is it because of the fact
that when JavaScript interpreter will come across this line it will
set "this" in "this.doAnimation" line to global window object as
setTimeout() is a method of global object? Does that sound good?
Moreover, having a closure like window.setTimeout(function()
{that.doAnimation()},33) works because Closures remember their context
and this is why "that" will point to correct "this"?

Can you please expand on that a bit? I will appreciate your help.

Thanks.
PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Oct 6 '08 #8
On Oct 6, 8:06 pm, Oltmans <rolf.oltm...@gmail.comwrote:
>
I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work? Is it because of the fact
that when JavaScript interpreter will come across this line it will
set "this" in "this.doAnimation" line to global window object as
setTimeout() is a method of global object?
No.

1.- Functions are objects, and the objects are passed by reference.
setTimeout expects (as a parameter) a reference to a function.

2.- 'this.doAnimation' is a property (of the object that 'this' points
to) that happens to hold a reference to a function.

3.- It is that reference what gets passed to setTimeout, and it holds
no relation with 'this' nor with the object that 'this' points to nor
with its 'doAnimation' property. That we have read it in the property
'doAnimation' of the object that 'this' points to, it doesn't matter.
Where it comes from is a don't care, it's just a reference to a
function.

Moreover, having a closure like window.setTimeout(function()
{that.doAnimation()},33) works because Closures remember their context
and this is why "that" will point to correct "this"?
1.- As the function (*) 'function() {that.doAnimation()}' has been
created in the context of the outer function, it too has access to the
same context.

2.- As long as a reference to that function (*) exists (in this case,
the reference that exists is the one passed to setTimeout), the
context won't/can't be destroyed by the garbage collector.

3.- And as 'that' is defined in the context, it's accesible from the
function (*) as well.

--
Jorge.
Oct 6 '08 #9
On Oct 6, 11:10*pm, Jorge <jo...@jorgechamorro.comwrote:
On Oct 6, 8:06 pm, Oltmans <rolf.oltm...@gmail.comwrote:
I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work? Is it because of the fact
that when JavaScript interpreter will come across this line it will
set "this" in "this.doAnimation" line to global window object as
setTimeout() is a method of global object?

No.

1.- Functions are objects, and the objects are passed by reference.
setTimeout expects (as a parameter) a reference to a function.

2.- 'this.doAnimation' is a property (of the object that 'this' points
to) that happens to hold a reference to a function.

3.- It is that reference what gets passed to setTimeout, and it holds
no relation with 'this' nor with the object that 'this' points to nor
with its 'doAnimation' property. That we have read it in the property
'doAnimation' of the object that 'this' points to, it doesn't matter.
Where it comes from is a don't care, it's just a reference to a
function.
And:

4.- If we call 'f' the reference to a function, then that's what your
code does:

this.doAnimation= f; -setTimeout(this.doAnimation, 33) ===
setTimeout(f, 33) -when setTimeout times out it calls f().

--
Jorge.
Oct 6 '08 #10
Oltmans wrote:
Thomas 'PointedEars' Lahn wrote:
>Gregor Kofler wrote:
>>var that = this;
...
window.setTimeout(that.doAnimation, 33);
Should be

window.setTimeout(function() { that.doAnimation() }, 33);

because with your code the method loses its connection to `that' (being
passed as just another Function object reference) and `this' in its
execution context will again refer to the Window or Global Object instead.

I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work?
I thought I had explained that above already.
Is it because of the fact that when JavaScript interpreter will come
across this line it will set "this" in "this.doAnimation" line to
global window object as setTimeout() is a method of global object?
No. First of all, the JavaScript interpreter (Virtual Machine) does not see
any of this. JavaScript source code is compiled into byte-code, which is
then interpreted/executed by a VM, just like Java (only that it is usually
JIT-compilation with JS).

Second, the compiler does not modify the meaning of symbols based on their
context. It is instead that if you pass `this.doAnimation' you are merely
passing a Function object reference (provided that `this.doAnimation' refers
to a Function object). When this Function object is called (here: by the
object referred to by `window') there is no telling which object's property
referred to it. So the `this' value initially does not refer to any object
(`null') which means that it is then set to the Global Object (that is not
necessarily the same as the object referred to by `window'). And that
object does not have a `doAnimation' property in either case.
Does that sound good?
Unfortunately, no.
Moreover, having a closure like window.setTimeout(function()
{that.doAnimation()},33) works because Closures remember their context
and this is why "that" will point to correct "this"?
Not quite. The function (expression) creates a closure, because there is
literally a bound variable here, `that'. It is a bound variable because
that variable is declared outside the function, and therefore its usage is
bound to that outer area. That outer area is the closure's definition
context (the context in which it was defined). That context is reproduced
when the function is called. Since `that' is (the identifier of) a variable
that has been assigned the `this' value within the definition context, it
stores a reference to the same object that `this' referred to, there and
then. That reference -- no pun intended -- can be used within the called
function then, no matter the caller.

Please trim your quotes to the necessary minimum, as you can see here.
PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Oct 6 '08 #11
Jorge wrote:
On Oct 6, 8:06 pm, Oltmans <rolf.oltm...@gmail.comwrote:
>I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work? Is it because of the fact
that when JavaScript interpreter will come across this line it will
set "this" in "this.doAnimation" line to global window object as
setTimeout() is a method of global object?

No.

1.- Functions are objects, and the objects are passed by reference.
No, all arguments are passed by value; object references are values.[1]
setTimeout expects (as a parameter) a reference to a function.
Or a string value, whereas the latter is slightly more compatible.
2.- 'this.doAnimation' is a property (of the object that 'this' points
to) that happens to hold a reference to a function.
[1^] See?
2.- As long as a reference to that function (*) exists (in this case,
the reference that exists is the one passed to setTimeout), the
context won't/can't be destroyed by the garbage collector.
True, however an implementation is free to provide a copy instead of a
reference, which would allow the source of this copy to be marked for
garbage collection.
PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Oct 6 '08 #12
On Oct 7, 4:17 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
Not quite. The function (expression) creates a closure, because there is
literally a bound variable here, `that'. It is a bound variable because
that variable is declared outside the function, and therefore its usage is
bound to that outer area. That outer area is the closure's definition
context (the context in which it was defined). That context is reproduced
when the function is called. Since `that' is (the identifier of) a variable
that has been assigned the `this' value within the definition context, it
stores a reference to the same object that `this' referred to, there and
then. That reference -- no pun intended -- can be used within the called
function then, no matter the caller.
OK. Thank you for explaining this. Very helpful. One last question.
setTimeout() expects function as its first argument. I guess both of
the following will work

a) window.setTimeout(aFunc,50);
where aFunc is defined as

function aFunc(){
alert('you will see me again');
}

b) window.setTimeout(function(){alert('you will see me again');},50);

My question is that if we can pass the Function Object Reference as
depicted in (a) then is it simply replaced with the function body e.g.
aFunc will be relpaced with the function aFunc(){alert('you will see
me again');}.

I mean if both (a) and (b) can do the job then why are there two ways
to do the same thing in the language. Any examples where passing
"Function object references" makes a difference while coding the
function as a parameter doesn't or vice-versa?

Please pardon my ignorance but I really am not sure about this.
Oct 7 '08 #13
dhtml wrote:
Oltmans wrote:
>On Oct 7, 4:17 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
nymous' function.

The former has an advantage in that if you want to say, remove an event
listener.

aDiv.addEventListener('click', aFunc, true);

If an anonymous function were used, it would not be possible to remove
it like so:-

aDiv.removeEventListener('click', aFunc, true);


Well technically the fucntion reference can be retained, but only
through being called:-

var b = document.body;
b.addEventListener('click', function(e){
alert(e);
b.removeEventListener('click', arguments.callee, false);
}, false);

by using arguments.callee in the call.
Oct 7 '08 #14
On Oct 7, 4:41 am, Oltmans <rolf.oltm...@gmail.comwrote:
>
OK. Thank you for explaining this. Very helpful. One last question.
setTimeout() expects function as its first argument. I guess both of
the following will work

a) window.setTimeout(aFunc,50);
where aFunc is defined as

function aFunc(){
alert('you will see me again');

}

b) window.setTimeout(function(){alert('you will see me again');},50);

My question is that if we can pass the Function Object Reference as
depicted in (a) then is it simply replaced with the function body e.g.
aFunc will be relpaced with the function aFunc(){alert('you will see
me again');}.

I mean if both (a) and (b) can do the job then why are there two ways
to do the same thing in the language. Any examples where passing
"Function object references" makes a difference while coding the
function as a parameter doesn't or vice-versa?

1.- A new, distinct instance of a function is created whenever a
function expression is encountered:

var fCollection= [], n= 1;

do {
fCollection[n]= function () { ; };
} while (n--)

alert(fCollection[0] === fCollection[1]); -false

But:

var fCollection= [], n= 1, f= function () { ; };

do {
fCollection[n]= f;
} while (n--)

alert(fCollection[0] === fCollection[1]); -true (obviously)
2.- Even when it's 'coded as a parameter', a reference to it is what
gets passed.

3.- The function 'coded as a parameter' gets created in the context in
which the function expression appears.

3.- Therefore, when 'coded as a parameter' you can tell for sure that
the function that gets passed has access to the context from which
you're passing it.

4.- But that might not be so if you're passing a function that was
created previously (one not 'coded as a parameter'):

function alertName () {
alert(typeof aName);
};

function test () {
var aName= "ok";
setTimeout(alertName, 0);
};

test(); -"undefined"

But:

function test () {
var aName= "ok";
function alertName () {
alert(typeof aName);
};
setTimeout(alertName, 0);
};

test(); -"string"

--
Jorge.
Oct 7 '08 #15
On Oct 7, 1:17 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
>
(..) The function (expression) creates a closure, because there is
literally a bound variable here, `that'. (..)

This phrase is a bit misleading: closures are created regardless of
variables, whenever an inner function is created in a context and it's
made available from outside of the context, and not because "there is
literally a bound variable".

<script>
window.onload= function () {
var that= '"that" is captured in a closure';

//No bound variables in the function expression:
setTimeout(function(){ alert(eval('th'+'at')) },500);
};
</script>

--
Jorge.
Oct 7 '08 #16
On Oct 7, 8:08 am, dhtml <dhtmlkitc...@gmail.comwrote:
>
Well technically the function reference can be retained, but only
through being called:-

var b = document.body;
b.addEventListener('click', function(e){
alert(e);
b.removeEventListener('click', arguments.callee, false);

}, false);

by using arguments.callee in the call.
Or saving a reference to it in the enclosing context:

var b= document.body, fReference;

b.addEventListener('click', (fReference= function(e){
alert(e);
b.removeEventListener('click', fReference, false);
}), false);

--
Jorge.
Oct 7 '08 #17
On Oct 7, 10:56 pm, Jorge <jo...@jorgechamorro.comwrote:
On Oct 7, 8:08 am, dhtml <dhtmlkitc...@gmail.comwrote:
Or saving a reference to it in the enclosing context:

var b= document.body, fReference;

b.addEventListener('click', (fReference= function(e){
alert(e);
b.removeEventListener('click', fReference, false);

}), false);

--
Jorge.
Thank you, Jorge and dhtml. Appreciate your time and help.
Oct 8 '08 #18
Jorge wrote:
Thomas 'PointedEars' Lahn wrote:
>(..) The function (expression) creates a closure, because there is
literally a bound variable here, `that'. (..)

This phrase is a bit misleading: closures are created regardless of
variables, whenever an inner function is created in a context and it's
made available from outside of the context, and not because "there is
literally a bound variable".
"Literally" is merely emphasizing the fact that it does not need to be a
variable in ECMAScript implementations:

<http://en.wikipedia.org/wiki/Closure_%28programming%29>
<script>
window.onload= function () {
var that= '"that" is captured in a closure';

//No bound variables in the function expression:
setTimeout(function(){ alert(eval('th'+'at')) },500);
};
</script>
Your example is not Valid and it is error-prone. That aside, `that' *is*
the bound variable here. It does not matter that the identifier does not
occur as-is in the source code of the called function.
PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm>
Oct 8 '08 #19
On Oct 8, 12:09*pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
Jorge wrote:
Thomas 'PointedEars' Lahn wrote:
(..) *The function (expression) creates a closure, because there is
literally a bound variable here, `that'. (..)
This phrase is a bit misleading: closures are created regardless of
variables, whenever an inner function is created in a context and it's
made available from outside of the context, and not because "there is
literally a bound variable".

"Literally" is merely emphasizing the fact that it does not need to be a
variable in ECMAScript implementations:

<http://en.wikipedia.org/wiki/Closure_%28programming%29>
Shorter, clearer, easier to understand, in a word : (Mmmuch) better,
explanation:

Closure

Functions can be defined inside of other functions. The inner function
has access to the vars and parameters of the outer function. If a
reference to an inner function survives (for example, as a callback
function), the outer function's vars also survive.

http://javascript.crockford.com/survey.html

HTH,
--
Jorge.
Oct 9 '08 #20

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: domeceo | last post by:
can anyone tell me why I cannot pass values in a setTimeout function whenever I use this function it says "menu is undefined" after th alert. function imgOff(menu, num) { if (document.images) {...
29
by: Mic | last post by:
Goal: delay execution of form submit Code (Javascript + JScript ASP): <% Response.Write("<OBJECT ID='IntraLaunch' STYLE='display : none' WIDTH=0 HEIGHT=0...
7
by: Antony Sequeira | last post by:
Hi While looking at some code I realized that the built in setTimeout function takes a string that is later evaluated in the original caller's context. How does one achieve something similar in...
5
by: oliver | last post by:
Hi, the structure of my source code is like this: <script> C = function(){ //some initialization } C.prototype.start = function{ //some action
6
by: Amy | last post by:
Hello, I have an array with 60 items in it, one for every second, But when it gets to the end of the 60 items it stops. How do I get it to start over when it gets to the end of the array? Please...
7
by: Martin | last post by:
Can I have two setTimeouts running at the same time - with two different intervals? I want to start one timer and, before it times out, start another one I've tried this and they seems to...
0
by: macaco | last post by:
Hi, I need a function that is called every certain amount of time (which is variable). I coded this, but seems to be making some sort of infinite loop, as it hangs the browser (or the OS on old...
6
by: Steve | last post by:
I have noticed that setTimeout works if the brackets () are left off the function called, like this: window.setTimeout(myFunction, 1000); I thought that the brackets were required to show that...
4
by: Ty | last post by:
Hello all, I am creating a web site with Visual Stuido 2008. I am trying to use a java script file to create a busybox for login from this page http://blogs.crsw.com/mark/articles/642.aspx. I...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.