开发者

Asynchronously delay JS until a condition is met

I have a class, ChatRoom, that can only render after it receives a long-running HTTP request (it could take 1 second or 30 seco开发者_如何学Gonds). So I need to delay rendering until ChatRoom.json is not null.

In the code below, I'm using Closure Library's goog.async.ConditionalDelay. It works, but is there a better way (maybe without needing Closure Library) to do this?

ChatRoom.prototype.json = null; // received after a long-running HTTP request.

ChatRoom.prototype.render = function() {
    var thisChatRoom = this;

    function onReady() {
        console.log("Received JSON", thisChatRoom.json);
        // Do rendering...
    }

    function onFailure() {
        alert('Sorry, an error occurred. The chat room couldn\'t open');
    }

    function isReady() {
        if (thisChatRoom.json != null) {
            return true;
        }
        console.log("Waiting for chat room JSON...");
        return false;
    }

    // If there is a JSON request in progress, wait until it completes.
    if (isReady()) {
        onReady();
    } else {
        var delay = new goog.async.ConditionalDelay(isReady);
        delay.onSuccess = onReady;
        delay.onFailure = onFailure;
        delay.start(500, 5000);
    }
}

Note that "while (json == null) { }" isn't possible because that would be synchronous (blocking all other JS execution).


Consider this:

(function wait() {
    if ( chatroom.json ) {
        chatroom.render();
    } else {
        setTimeout( wait, 500 );
    }
})();

This will check every half second.

Live demo: http://jsfiddle.net/kBgTx/


You could also achieve this using lodash's debouncer with recursion.

import _debounce from 'lodash/debounce';

const wait = (() => {
    if ( chatroom.json ) {
        chatroom.render();
    } else {
      _debounce(wait, 500)();
    }
})();


we can use await new Promise((resolve) and call resolve when our condition is true : we can run whole code in browser with audioPermission On.

(async () => {
const getVolume = async () => {
let n = 0;
let abc = async () => {
  let count = 0;
  try {
    let audioStream = await navigator.mediaDevices.getUserMedia({
      audio: {
        echoCancellation: true,
      },
    });
    let audioContext = new AudioContext();

    let audioSource = audioContext.createMediaStreamSource(audioStream);
    let analyser = audioContext.createAnalyser();
    analyser.fftSize = 512;
    analyser.minDecibels = -127;
    analyser.maxDecibels = 0;
    analyser.smoothingTimeConstant = 0.4;
    audioSource.connect(analyser);
    let volumes = new Uint8Array(analyser.frequencyBinCount);
    console.log("volume__________________");
    console.log(volumes);

    await new Promise((resolve) => {
      const timer = setInterval(() => {
        count += 1;
        console.log("count = " + count);

        analyser.getByteFrequencyData(volumes);
        console.log("volume__________________");
        console.log(volumes);

        if (count == 3 || volumes[0] > 0) {
          clearInterval(timer);
          n = volumes[0];
          console.log("count__________________" + count);
          resolve(n);
        }
      }, 2000);
    });
  } catch (e) {
    console.error(
      "Failed to initialize volume visualizer, simulating instead...",
      e
    );
    return 0;
  }

  console.log("n inside______________ = " + n);
  return n;
};

await abc();

return n;
};

let t = await getVolume();
console.log(t);
})();


The answer I came up with is like this:

var count = 0;
// Number of functions that need to run. This can be dynamically generated
// In this case I call check(data, cb) a total of 3 times
var functionNum = 3; 
function toCallAfter(){
    console.log('I am a delayed function');
}

I had this for a check function that ran once regularly and twice in a loop:

check(data, function(err){ // check is my asynchronous function to check data integrity
    if (err){
        return cb(null, { // cb() is the return function for the containing function
            errCode: 'MISSINGINFO',
            statusCode: 403,
            message : 'All mandatory fields must be filled in'
        });
    } // This part here is an implicit else
    count++; // Increment count each time required functions complete to
             // keep track of how many function have completed
    if (count === functionNum) {
        return anon();
    }
    return;
});
// Run twice more in a loop
for(var i = 0; i < 2; i++) {
    check(data, function(err) { // calls check again in a loop
        if (err){
            return cb(null, {
                errCode: 'MISSINGINFO',
                statusCode: 403,
                message : 'All mandatory fields must be filled in'
            });
        }
        count++;
        if (count === functionNum) {
            return toCallAfter();
        }
        return;
    });
}

Lastly, I'd like to point out a significant performance fault in the alternate (and extraordinarily common) answer:

(function wait() {
    if ( chatroom.json ) {
        chatroom.render();
    } else {
        setTimeout( wait, 500 );
    }
})();

In this case, you are essentially holding the browser or server (If using node.js) hostage for 500 milliseconds for every check which is an incredibly long time for a computer. Meaning a huge performance hit. My solution of directly keeping track of the required completed functions is free from time restraints and will run instantly as soon as all functions complete.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜