0

I'm trying to slim down some repetitive code that worked before by using a for loop to iterate through the process for a list of objects.

var context = new (window.AudioContext || window.webkitAudioContext)();

//Set up the objects for each part
var solo = { audio: context.createBufferSource(),
     audioData: context.createBufferSource(),
     file: "mp3s/Faith_solo.mp3",
     request: new XMLHttpRequest(),
     isPlaying: false,
     startTime: null,
     seekAsOfLastPause: 0,
     duration: 0
        }
var t1 = { audio: context.createBufferSource(),
   audioData: context.createBufferSource(),
   file: "mp3s/Faith_t1.mp3",
   request: new XMLHttpRequest(),
   isPlaying: false,
   startTime: null,
   seekAsOfLastPause: 0,
   duration: 0
     }
var t2 = { audio: context.createBufferSource(),
   audioData: context.createBufferSource(),
   file: "mp3s/Faith_t2.mp3",
   request: new XMLHttpRequest(),
   isPlaying: false,
   startTime: null,
   seekAsOfLastPause: 0,
   duration: 0
        }
var baritone = {
     audio: context.createBufferSource(),
     audioData: context.createBufferSource(),
     file: "mp3s/Faith_baritone.mp3",
     request: new XMLHttpRequest(),
     isPlaying: false,
     startTime: null,
     seekAsOfLastPause: 0,
     duration: 0
        }
var bass = { audio: context.createBufferSource(),
     audioData: context.createBufferSource(),
     file: "mp3s/Faith_bass.mp3",
     request: new XMLHttpRequest(),
     isPlaying: false,
     startTime: null,
     seekAsOfLastPause: 0,
     duration: 0
       }

var allParts = [solo, t1, t2, baritone, bass];

/* create requests, send requests, load files */

for(i=0;i<allParts.length;i++){
    allParts[i].request.open("GET", allParts[i].file, true);
    allParts[i].request.responseType = "arraybuffer";
    allParts[i].request.onload = function(){
        **context.decodeAudioData(allParts[i].request.response, onDecoded);**
    }
    function onDecoded(buffer){
        allParts[i].audioData.buffer = buffer;
    }
    allParts[i].request.send();
}

I'm getting five copies of the error: "Uncaught TypeError: Cannot read property 'request' of undefined at XMLHttpRequest.allParts.(anonymous function).request.onload" on the line surrounded by asterisks where I set up the context.decodeAudioData parameters.

I'm not quite sure why this is. I've been told this is a closure problem, but I've been unable to find a way to fix it, and I don't quite understand why it would be a closure problem. The XMLHttpRequest is created before that code runs, and it's outside of the scope of the anonymous function, so it should be accessible there.

Thanks for any help!

Josh
  • 1
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – PeterMader Jul 01 '17 at 16:45
  • Thanks for linking this. I looked through and changed the for loops to forEachs and it looked to fix the issue! – Josh Jul 01 '17 at 17:14

1 Answers1

0

You need to define i in your loop using let. Or use forEach or allParts.map

for(let i=0;i<allParts.length;i++){ ...

or

allParts.map(function(part, i){ ... })
Khauri
  • 3,753
  • 1
  • 11
  • 19
  • Yep, that looked to about do it. I updated the functions to use forEach. Thanks so much! – Josh Jul 01 '17 at 17:13