Repository: mrdoob/three.js (JavaScript)
Date: 2019-11-14 19:29:58+00:00
Task type: Bug Fix

Issue:
LoadingManager.getHandler does not work half the time if a regex with g flag is passed
If adding a handler with a regex that has the `g` flag, the `regex.test` in `getHandler` will return null every other time.
I think `string.match` should be used rather than `regex.test` to avoid any side effect like this




Issue discussion:
Could you share an example to reproduce this issue?
Here you go @donmccurdy 
https://jsfiddle.net/qkwx4Lg1/2
so basically this:
![Screen Shot 2019-11-14 at 13 13 21 ](https://user-images.githubusercontent.com/242577/68856359-962a0a80-06e0-11ea-9e6c-511bfcd4bcd4.png)
mozdev says:
> As with exec() (or in combination with it), test() called multiple times on the same global regular expression instance will advance past the previous match.

apparently you can do this to keep using `test()`:
![Screen Shot 2019-11-14 at 13 20 01 ](https://user-images.githubusercontent.com/242577/68856744-8eb73100-06e1-11ea-83f5-46db149a69a1.png)

> If adding a handler with a regex that has the g flag

May I ask, why are you adding the `g` flag in the first place? Normally the regex applied to `addHandler()` should always have this structure: `/\.tga$/i`.
> > If adding a handler with a regex that has the g flag
> 
> May I ask, why are you adding the `g` flag in the first place? Normally the regex applied to `addHandler()` should always have this structure: `/\.tga$/i`.

I just took the habit to add g, and didn't think too much about it. Nevertheless, calls to `getHandler` should be consistant
@makc Using `lastIndex` seems like an appropriate solution 👍 

Solution patch:
diff --git a/src/loaders/LoadingManager.js b/src/loaders/LoadingManager.js
--- a/src/loaders/LoadingManager.js
+++ b/src/loaders/LoadingManager.js
@@ -121,6 +121,8 @@ function LoadingManager( onLoad, onProgress, onError ) {
 			var regex = handlers[ i ];
 			var loader = handlers[ i + 1 ];
 
+			if ( regex.global ) regex.lastIndex = 0; // see #17920
+
 			if ( regex.test( file ) ) {
 
 				return loader;


Test patch:
diff --git a/test/unit/src/loaders/LoadingManager.tests.js b/test/unit/src/loaders/LoadingManager.tests.js
--- a/test/unit/src/loaders/LoadingManager.tests.js
+++ b/test/unit/src/loaders/LoadingManager.tests.js
@@ -4,6 +4,7 @@
 /* global QUnit */
 
 import { LoadingManager } from '../../../../src/loaders/LoadingManager';
+import { Loader } from '../../../../src/loaders/Loader';
 
 export default QUnit.module( 'Loaders', () => {
 
@@ -59,6 +60,28 @@ export default QUnit.module( 'Loaders', () => {
 
 		} );
 
+		QUnit.test( "getHandler", ( assert ) => {
+
+			const loadingManager = new LoadingManager();
+			const loader = new Loader();
+
+			const regex1 = /\.jpg$/i;
+			const regex2 = /\.jpg$/gi;
+
+			loadingManager.addHandler( regex1, loader );
+
+			assert.equal( loadingManager.getHandler( 'foo.jpg' ), loader, 'Returns the expected loader.' );
+			assert.equal( loadingManager.getHandler( 'foo.jpg.png' ), null, 'Returns null since the correct file extension is not at the end of the file name.' );
+			assert.equal( loadingManager.getHandler( 'foo.jpeg' ), null, 'Returns null since file extension is wrong.' );
+
+			loadingManager.removeHandler( regex1 );
+			loadingManager.addHandler( regex2, loader );
+
+			assert.equal( loadingManager.getHandler( 'foo.jpg' ), loader, 'Returns the expected loader when using a regex with "g" flag.' );
+			assert.equal( loadingManager.getHandler( 'foo.jpg' ), loader, 'Returns the expected loader when using a regex with "g" flag. Test twice, see #17920.' );
+
+		} );
+
 	} );
 
 } );