I have this code that I need to convert to async loop since obviously this code for-loop will block the UI/Browser:
$wnd.mainbuff = [];
$wnd.update = setInterval(function(){
// fetches everything in the buffer (csv), including old data
var temp = $wnd.Recorder.audioData().toString();
var arr = temp.split(',');
// so, copy new elements only (must be async)
for (var i=$wnd.mainbuff.length; i < arr.length; i++) {
console.log(arr[i]);
$wnd.mainbuff[i] = arr[i];
}
}
,25)
Turn your loop into an equivalent recursive function. It then will be easy to use setTimeout when calling itself.
$wnd.mainbuff = [];
$wmd.curTimerId = null;
$wnd.update = function() {
var start = Date.now();
// fetches everything in the buffer (csv), including old data
// doesn't sound good ^^^^^^^^
var temp = $wnd.Recorder.audioData().toString();
var arr = temp.split(',');
// so, copy new elements only
function processOne(i, callback) {
if (i < arr.length) {
console.log(arr[i]);
$wnd.mainbuff[i] = arr[i];
setTimeout(function(){processOne(i+1, callback);}, 0);
} else
callback();
}
processOne($wnd.mainbuff.length, function() {
setTimeout($wnd.update, 25- (Date.now()-start));
});
}
Try this:
$wnd.mainbuff = [];
function async(arr, wnd, currentIndex) {
console.log(arr[currentIndex]);
wnd.mainbuff[currentIndexi] = arr[currentIndexi];
}
$wnd.update = setInterval(function(){
// fetches everything in the buffer (csv), including old data
var temp = $wnd.Recorder.audioData().toString();
var arr = temp.split(',');
// so, copy new elements only (must be async)
for (var i=$wnd.mainbuff.length; i < arr.length; i++) {
async(arr, $wnd, i);
}
}
,25)
Related
I'm trying the following logic and not sure which array function can help. I'm not able to use map or es6 but would like to see an answer.
I tried the following:
/* JS */ - This is not working and would like to see how to make it work.
var input = ['x','y','z'];
var powerSetResult = powerSet(input);
console.log(powerSetResult);
/*Ouput should be [''.'x','y','z','xy,'xz','yz','xyz']*/
function powerSet(arr) {
var data = [];
for(var i=0; i<arr.length; i++) {
arr[i] = arr[i] + arr[i+1];
data.push(arr[i]);
}
console.log(data);
return data;
}
/* ES 6 */ - Is there a better way to do this?
let input = ['x','y','z'];
let powerSetResult = powerSet(input);
console.log(powerSetResult);
/*Ouput should be [''.'x','y','z','xy,'xz','yz','xyz']*/
const powerSet(arr) {
let data = arr.map(([s1, s2, s3]) => [``,`${s1}`,`${s2}`,`${s3}`,`${s1}${s2}`,`${s1}${s3}`,`${s2}${s3}`,`${s1}${s2}${s3}`]);
console.log(data);
return data;
}
Certainly not the most efficient... but you could do this:
var input = ['x','y','z'];
var powerSetResult = powerSet(input);
console.log(powerSetResult);
function powerSet(arr, result) {
result = result || new Set();
const str = arr.join('');
for (let i = 0; i < arr.length; i++) {
for (let j = i; j <= arr.length; j++) {
result.add(str.slice(i, j));
}
powerSet([...arr.slice(0, i), ...arr.slice(i+1)], result)
}
return Array.from(result).sort((a, b) => {
return (a.length - b.length) || a.localeCompare(b);
});
}
/* Output should be [''.'x','y','z','xy,'xz','yz','xyz'] */
Caveat being it will only work for single letter elements, but is easily modifiable to accommodate more.
I have an async function named populateFavoriteItem in for loop :
var result = [];
for (var i = 0; i <array.length ; i++) {
populateFavoriteItem(accountId,array[i],function(doc){
result.push(doc);
//mark 1
})
// if (i == array.length - 1) {
// console.log(result);
// callback(result);
// }
}
//mark 2
console.log(result);
callback(result);
It always run mark 2 first and then run to mark 1. Therefore, I get a null result array. Seems that result is not the populateFavoriteItem callback function.
Im trying to write if() condition in the for loop but get the same consequence, what should I do?
Use Node.js eventEmitter:
var result = [];
var obj;
var j = 0;
var myEventEmitter = new eventEmitter;
myEventEmitter.on('next',addResult);
function addResult(){
result.push(obj)
j++;
if (j == array.length) {
callback(result);
}
}
var populateFav = promiseify(populateFavoriteItem);
for (var i = 0; i <array.length ; i++) {
var ii = i;
populateFavoriteItem(accountId,array[ii],function(doc){
//result.push(doc);
obj = doc;
myEventEmitter.emit("next");
})
}
I have this code and I want to make the code wait until the asyncrnous query called prom has finessed before restarting the first for loop. So the array will be reset, before it starts the first for loop again.
items = [];
var promises = [];
for (var i = 0; i < userArray.length; i++) {
items.length = 0;
for (var i2 = 0; i2 < test.length; i2++) {
var UserFavourite = Parse.Object.extend("UserFavourite");
var queryUserFav = new Parse.Query(UserFavourite);
queryUserFav.equalTo('item', test[i2].get('item'));
queryUserFav.equalTo('school', test[i2].get('school'));
queryUserFav.equalTo('user1', userArray[i])
var prom = queryUserFav.find().then(function(res) {
for (var i3 = 0; i3 < res.length; i3++){
var item = res[i3];
var itemName = item.get('item');
items.push(itemName);
console.log(items)
}
return items;
});
promises.push(prom);
}
//return Parse.Promise.when.apply(Parse.Promise, promises); I have tried it here but
// this just stops the first for loop after its first loop
}
return Parse.Promise.when.apply(Parse.Promise, promises);
What you're trying to do is have a chain of promises, one for each item in an array.
If would be nice if javascript had an equivalent of .NET's await keyword, where you could go
await Parse.Promise.when(promises)
and then it allowed the promise code to run then returned back to running any code after the await. But Javascript doesn't give this to us.
Another approach is to maintain an index variable. After every set of queries is processed, you increment the index variable and process the next set of values.
function parseForUser(user) {
var promises = [];
for (var i2 = 0; i2 < test.length; i2++) {
var items = [];
var UserFavourite = Parse.Object.extend("UserFavourite");
var queryUserFav = new Parse.Query(UserFavourite);
queryUserFav.equalTo('item', test[i2].get('item'));
queryUserFav.equalTo('school', test[i2].get('school'));
queryUserFav.equalTo('user1', user)
var prom = queryUserFav.find().then(function(res) {
for (var i3 = 0; i3 < res.length; i3++){
var item = res[i3];
var itemName = item.get('item');
items.push(itemName);
console.log(items)
}
return items;
});
promises.push(prom);
}
return Parse.Promise.when(promises);
}
function parseUserArray(userArray) {
var returnPromise = new Parse.Promise(); // Do you have to call it via new?
//The documentation isn't clear.
var index = 0;
var doNext = function() {
if(index < userArray.length) {
var promise = parseForUser(userArray[index++]);
promise.done(doNext);
} else {
returnPromise.resolve();
}
}
doNext();
return returnPromise;
}
var parseUserArrayPromise = parseUserArray(userArray);
FWIW ...
This solution differs from #AndrewShepherd's chiefly in that here we take double advantage of the promise returned by asyncProcessUser().
firstly for flow control - the asynchronous sequencing of the inner loop
secondly for delivering an array of results, from which the final array of results is built, avoiding the need for an outer promises array.
function parseUserArray(userArray, test) {
// This function is the original inner for() loop, now expressed as a .map(),
// (plus peripheral wrapping and chaining).
// It asynchronously processes a single user against all test items,
// and returns a promise of an array of results.
// The promise resolves when all the individual .finds complete.
function asyncProcessUser(user) {
return Parse.Promise.when(test.map(function(dataItem) {
return (new Parse.Query(Parse.Object.extend("UserFavourite")))
.equalTo('item', dataItem.get('item'))
.equalTo('school', dataItem.get('school'))
.equalTo('user1', user)
.find().then(function(res) {
return res.map(function(r) {
return r.get('item');
});
});
})).then(function() {
return Array.prototype.slice.apply(arguments).reduce(function(arr, arr_) {
return arr.concat(arr_);
}, []);
});
}
// This is the original outer for() loop, now expressed as a .reduce(), which is
// a common pattern for performing a series of async tasks (ie what was the inner loop).
// Here, `userArray.reduce(...)` returns a promise of an array of
// the objects returned by `r.get('item')` above.
return userArray.reduce( function(p, user) {
return p.then(function(arr) {
return asyncProcessUser(user).then(function(arr_) {
return arr.concat(arr_);
});
});
}, Parse.Promise.as([]) );//† "returns a new promise that is resolved with a given value".
}
† : Documentation for Parse.Promise.as()
Without the comments, it's quite concise.
The concept is demonstrated here. Don't worry that the demo uses jQuery promises, it's the concept that matters.
Use this
function parseForUser(user) {
var promises = [];
for (var i2 = 0; i2 < test.length; i2++) {
var items = [];
var UserFavourite = Parse.Object.extend("UserFavourite");
var queryUserFav = new Parse.Query(UserFavourite);
queryUserFav.equalTo('item', test[i2].get('item'));
queryUserFav.equalTo('school', test[i2].get('school'));
queryUserFav.equalTo('user1', user)
var prom = queryUserFav.find().then(function(res) {
for (var i3 = 0; i3 < res.length; i3++){
var item = res[i3];
var itemName = item.get('item');
items.push(itemName);
console.log(items)
}
return items;
});
promises.push(prom);
}
return Parse.Promise.when(promises);
}
function parseUserArray(userArray) {
var returnPromise = new Parse.Promise(); // Do you have to call it via new?
//The documentation isn't clear.
var index = 0;
var doNext = function() {
if(index < userArray.length) {
var promise = parseForUser(userArray[index++]);
promise.done(doNext);
} else {
returnPromise.resolve();
}
}
doNext();
return returnPromise;
}
Just copy and paste
I create an array like so
var membersList = $('#chatbox_members' , avacweb_chat.doc.body).find('li');
var onlineUsers = [];
var offLineUsers = [];
for(var i =0;i<membersList.length;i++){
var name = $(membersList[i]).text().replace("#","");
onlineUsers.push(name);
}
alert(onlineUsers);
listedUsers would come out something like so [Mr.EasyBB,Tonight,Tomorrow,Gone];
Question is if I use a two for loops one outside a setInterval and one inside to compare-
var membersList = $('#chatbox_members' , _chat.doc.body).find('li');
var onlineUsers = [];
var offLineUsers= [];
for(var i =0;i<membersList.length;i++){
var name = $(membersList[i]).text().replace("#","");
onlineUsers.push(name);
}
var int = setInterval(function() {
var newMember = ('#chatbox_members' , _chat.doc.body).find('li');
for(var i =0;i<newMember.length;i++){
var name = $(newMember[i]).text().replace("#","");
offLineUsers.push(name);
}
Which then would get:
onlineUsers = [Mr.EasyBB,Tonight,Tomorrow,Gone];
offLineUsers = [Mr.EasyBB,Tonight];
So to get the offline users I want to basically replace onlineUsers with offLineUsers which then should return Tomorrow,Gone . Though I know that an object doesn't have the function to replace so how would I go about this?
I don't think the splice function would work since you need to have parameters, and pop or shift are beginning and end of array.
for(var i = 0 ; i < offLineUsers.length ; i++)
{
for(var j = 0 ; j < onlineUsers.length ; j++)
{
if(onlineUsers[j] == offLineUsers[i])
{
onlineUsers.splice(j,1);
}
}
}
Try this snippet.
If I have understand well, maybe that helps:
function bus_dup() {
for(var i = 0; i < offLineUsers.length; i++) {
onLineUsers.splice(onLineUsers.indexOf(offLineUsers[i]),1);
}
offLineUsers = [];
}
This should do what you are looking for on a modern browser, using array.filter
var onlineUsers = ["Mr.EasyBB", "Tonight", "Tomorrow", "Gone"];
var offLineUsers = ["Mr.EasyBB", "Tonight"];
function discord(online, offline) {
return online.filter(function (element) {
return offline.indexOf(element) === -1;
});
}
console.log(discord(onlineUsers, offLineUsers));
Output
["Tomorrow", "Gone"]
On jsfiddle
If you want the difference regardless of the order of attributes passed to the function then you could do this.
var onlineUsers = ["Mr.EasyBB", "Tonight", "Tomorrow", "Gone"];
var offLineUsers = ["Mr.EasyBB", "Tonight"];
function difference(array1, array2) {
var a = array1.filter(function (element) {
return array2.indexOf(element) === -1;
});
var b = array2.filter(function (element) {
return array1.indexOf(element) === -1;
});
return a.concat(b);
}
console.log(difference(onlineUsers, offLineUsers));
console.log(difference(offLineUsers, onlineUsers));
Output
["Tomorrow", "Gone"]
["Tomorrow", "Gone"]
On jsfiddle
I'd like to split a string ("1,2,3") and return it as an int array so I wrote the following function:
function stringToIntArray(string) {
var split = {};
split = string.split(',');
var selected = {};
for (var i = 0; i <= split.length; i++) {
selected[i] = split[i];
}
return selected;
}
However split.length is always undefinied. Where's my mistake?
var selected = {};
doesn't build an array but an object, which has no length property.
You can fix your code by replacing it with
var selected = [];
If you want to return an array of numbers, you can change your code to
function stringToIntArray(string) {
var split = string.split(',');
var selected = [];
for (var i = 0; i < split.length; i++) {
selected.push(parseInt(split[i], 10));
}
return selected;
}
Note that I replaced <= with < in your loop.
Note also that for modern browsers, you can use the map function to make it simpler :
function stringToIntArray(string) {
return string.split(',').map(function(v){ return parseInt(v, 10) });
}