5

I have a module:

var progress = {
    val: 0
};

var service = (function(){

    function someMethod(){
        progress.val++;
    }

    return{
        someMethod: someMethod
    };

})();

export {service,progress}

someMethod will perform an operation where an array is iterated. I would like to increment progress.val by one at each iteration. This progress should then be observable:

  System.import('components/Service.js')
   .then(function(M){
            self.progress = M.progress;

           Object.observe(M.progress,function(c){
               console.dir(c);
           });
       });

Unfortunately, the observers callback is invoked only once, holding an array of changes with one item per iteration.

How can I invoke the callback on each iteration?

user2422960
  • 1,276
  • 5
  • 15
  • 27
  • 1
    This actually has nothing to do with modules, so you might want to think about changing the title of your question. –  Mar 30 '15 at 07:11
  • if you want sync behavior, you can kill the Object.observe and use a getter/setter instead, something less old-fashioned but similar to http://jsfiddle.net/g35orqrq/ – dandavis Apr 06 '15 at 00:28

1 Answers1

4

That's how object observing works.

The observer will only fire at the next tick of the clock with a collection of records. It does not fire synchronously on individual changes as they are made. See also Object.Observe Synchronous Callback.

To accomplish what you want, one approach is to rewrite your iterator so that it "sleeps" each time through the loop to give Object.observe a chance to fire. I'm not necessarily recommending this precise approach, but just as an example:

function iterate(a, fn) {
    (function loop() {
        if (!a.length) return;
        fn(a.shift());
        setTimeout(loop); 
    })();
}

Now, any changes to properties made on the observe object by fn will be reported during that iteration of the loop.

You could accomplish the same thing using promises:

function iterate(a, fn) {
    a.reduce((p, e) => p.then(() => fn(e)), Promise.resolve());
}

If you happen to be in an async/await environment (this is an ES7 feature, but available in transpilers such as Babel), then you could also do the following, which under the covers is about equivalent to the promises approach above:

async function iterate(a, fn) {
    for (i of a) await fn(i);
}

As an aside, You don't need an IIFE here. Also, self is not declared--I expect a run-time error on the self.progress = M.progress line.

Community
  • 1
  • 1