FileLoader.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import { Cache } from './Cache.js';
  2. import { Loader } from './Loader.js';
  3. const loading = {};
  4. class FileLoader extends Loader {
  5. constructor( manager ) {
  6. super( manager );
  7. }
  8. load( url, onLoad, onProgress, onError ) {
  9. if ( url === undefined ) url = '';
  10. if ( this.path !== undefined ) url = this.path + url;
  11. url = this.manager.resolveURL( url );
  12. const cached = Cache.get( url );
  13. if ( cached !== undefined ) {
  14. this.manager.itemStart( url );
  15. setTimeout( () => {
  16. if ( onLoad ) onLoad( cached );
  17. this.manager.itemEnd( url );
  18. }, 0 );
  19. return cached;
  20. }
  21. // Check if request is duplicate
  22. if ( loading[ url ] !== undefined ) {
  23. loading[ url ].push( {
  24. onLoad: onLoad,
  25. onProgress: onProgress,
  26. onError: onError
  27. } );
  28. return;
  29. }
  30. // Initialise array for duplicate requests
  31. loading[ url ] = [];
  32. loading[ url ].push( {
  33. onLoad: onLoad,
  34. onProgress: onProgress,
  35. onError: onError,
  36. } );
  37. // create request
  38. const req = new Request( url, {
  39. headers: new Headers( this.requestHeader ),
  40. credentials: this.withCredentials ? 'include' : 'same-origin',
  41. // An abort controller could be added within a future PR
  42. } );
  43. // start the fetch
  44. fetch( req )
  45. .then( response => {
  46. if ( response.status === 200 || response.status === 0 ) {
  47. // Some browsers return HTTP Status 0 when using non-http protocol
  48. // e.g. 'file://' or 'data://'. Handle as success.
  49. if ( response.status === 0 ) {
  50. console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
  51. }
  52. const callbacks = loading[ url ];
  53. const reader = response.body.getReader();
  54. const contentLength = response.headers.get( 'Content-Length' );
  55. const total = contentLength ? parseInt( contentLength ) : 0;
  56. const lengthComputable = total !== 0;
  57. let loaded = 0;
  58. // periodically read data into the new stream tracking while download progress
  59. return new ReadableStream( {
  60. start( controller ) {
  61. readData();
  62. function readData() {
  63. reader.read().then( ( { done, value } ) => {
  64. if ( done ) {
  65. controller.close();
  66. } else {
  67. loaded += value.byteLength;
  68. const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } );
  69. for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
  70. const callback = callbacks[ i ];
  71. if ( callback.onProgress ) callback.onProgress( event );
  72. }
  73. controller.enqueue( value );
  74. readData();
  75. }
  76. } );
  77. }
  78. }
  79. } );
  80. } else {
  81. throw Error( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}` );
  82. }
  83. } )
  84. .then( stream => {
  85. const response = new Response( stream );
  86. switch ( this.responseType ) {
  87. case 'arraybuffer':
  88. return response.arrayBuffer();
  89. case 'blob':
  90. return response.blob();
  91. case 'document':
  92. return response.text()
  93. .then( text => {
  94. const parser = new DOMParser();
  95. return parser.parseFromString( text, this.mimeType );
  96. } );
  97. case 'json':
  98. return response.json();
  99. default:
  100. return response.text();
  101. }
  102. } )
  103. .then( data => {
  104. // Add to cache only on HTTP success, so that we do not cache
  105. // error response bodies as proper responses to requests.
  106. Cache.add( url, data );
  107. const callbacks = loading[ url ];
  108. delete loading[ url ];
  109. for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
  110. const callback = callbacks[ i ];
  111. if ( callback.onLoad ) callback.onLoad( data );
  112. }
  113. this.manager.itemEnd( url );
  114. } )
  115. .catch( err => {
  116. // Abort errors and other errors are handled the same
  117. const callbacks = loading[ url ];
  118. delete loading[ url ];
  119. for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
  120. const callback = callbacks[ i ];
  121. if ( callback.onError ) callback.onError( err );
  122. }
  123. this.manager.itemError( url );
  124. this.manager.itemEnd( url );
  125. } );
  126. this.manager.itemStart( url );
  127. }
  128. setResponseType( value ) {
  129. this.responseType = value;
  130. return this;
  131. }
  132. setMimeType( value ) {
  133. this.mimeType = value;
  134. return this;
  135. }
  136. }
  137. export { FileLoader };
粤ICP备19079148号