It is possible, when I would unsubscribe an connectable observable and at later time to connect it again.
For example:
var interval = Rx.Observable.interval(1000);
var source = interval
.take(2)
.do(function (x) {
console.log('Side effect');
});
var published = source.publish();
published.subscribe(createObserver('SourceA'));
published.subscribe(createObserver('SourceB'));
// Connect the source
var connection = published.connect();
function createObserver(tag) {
return Rx.Observer.create(
function (x) {
console.log('Next: ' + tag + x);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});
}
Yes it is. This is exactly what operator refCount() does. It subscribes and unsubscribes a ConnectableObservable.
See: https://github.com/ReactiveX/rxjs/blob/master/src/observable/ConnectableObservable.ts
Related
How can I stop a setTimeout function before starting from the onWrite event on a "Firebase Cloud Function"? I try with setTimeout, but the clearTimeout do not stop the setTimeout.
P.S.: I've already raised the script timeout from the Firebase panel from 60 seconds (default) to 360 seconds.
var timeOutOnline = {};
exports.online = functions.database.ref('/server/{serverId}/online/time').onWrite(event => {
const serverId = event.params.serverId;
var time = event.data.val();
var lastDateOnline = new Date( time * 1000);
var dateString = lastDateOnline.toGMTString();
clearTimeout(timeOutOnline[serverId]);
refGet = db.ref('/server/'+serverId+'/online/');
refGet.once('value').then(function(snapshot) {
var onlineSnap = snapshot.val();
if (onlineSnap && onlineSnap.alarm == true) {
sendMail(serverId,false, 'not responding' , 'Server '+ serverId + ' not responding from '+dateString);
setAlarmStatus(serverId,false);
} else {
timeOutOnline[serverId] = setTimeout(function() {
sendMail(serverId,true, 'not responding' , 'Server '+ serverId + ' not responding from '+dateString);
setAlarmStatus(serverId,true);
}, 21000);
}
});
return true;
});
UPDATE:
Now I use promise, but clearTimeout still not working, not clearing setTimeout function. What am I doing wrong?
var timeOutOnline = {};
exports.online = functions.database.ref('/server/{serverId}/online/time').onWrite(event => {
const serverId = event.params.serverId;
var time = event.data.val();
var lastDateOnline = new Date( time * 1000);
var dateString = lastDateOnline.toGMTString();
console.log(v);
if(!timeOutOnline[serverId]) {
timeOutOnline[serverId] = [];
} else {
timeOutOnline[serverId].length;
for (var i = 0; i < timeOutOnline[serverId].length; i++) {
if (timeOutOnline[serverId][i]) {
timeOutOnline[serverId][i].cancel();
timeOutOnline[serverId][i] = null;
}
}
}
timeOutOnline[serverId] = timeOutOnline[serverId].filter(n => n);
refGet = db.ref('/server/'+serverId+'/online/');
refGet.once('value').then(function(snapshot) {
var onlineSnap = snapshot.val();
if (onlineSnap && onlineSnap.alarm == true) {
sendMail(serverId,false, 'not responding' , 'Server '+ serverId + ' not responding from '+dateString);
setAlarmStatus(serverId,false);
} else {
timeOutOnline[serverId].push(waitForServer(210000));
var index = timeOutOnline[serverId].length - 1;
return timeOutOnline[serverId][index].promise.then(function(i) {
console.log('Server '+ serverId + ' not responding from '+dateString);
sendMail(serverId,true, 'not responding' , 'Server '+ serverId + ' not responding from '+dateString);
setAlarmStatus(serverId,true);
});
}
});
return true;
});
function waitForServer(ms) {
var timeout, promise;
promise = new Promise(function(resolve, reject) {
timeout = setTimeout(function() {
resolve('timeout done');
}, ms);
});
return {
promise:promise,
cancel:function(){
console.log('cancel timeout: '+timeout);
clearTimeout(timeout);
}
};
}
There's a lot of things wrong in this function.
First of all, it's not clear to me why you want to use setTimeout() in this function. In fact, there are almost no valid use cases for setTimeout() with Cloud Functions. Functions are supposed to execute as fast as possible, and setTimeout only really just incurs extra cost to your processing. Cloud Functions does not enable you to run "background work" that survives past the invocation of the function - that's just not how it works.
Second of all, you're performing async work here, but you're not returning a promise to indicate when that work completes. If you don't return a promise that's resolved when your work completes, your function is highly likely to exhibit strange problems, including work not completing as you'd expect.
i have tried out the documented example for RXJS pausable and while it pauses ok it resets on resume. how do i modify the example below to have my stream resume from where i paused it rather than reset?
var pauser = new Rx.Subject();
var source = Rx.Observable
.interval(1000)
.timeInterval()
.pausable(pauser);
var subscription = source.subscribe(
function (x) {
$("#result").append('Next: ' + JSON.stringify(x) + '<br>');
},
function (err) {
$("#result").append('Error: ' + err);
},
function () {
$("#result").append('Completed');
});
pauser.onNext(true);
var paused = false;
$("#result").click(function() {
$(this).append("mouse clicked");
paused = (paused === false) ? true : false;
pauser.onNext(paused);
});
this is giving me the following output:
Next: {"value":0,"interval":1002}
Next: {"value":1,"interval":1000}
Next: {"value":2,"interval":999}
mouse clicked
mouse clicked
Next: {"value":0,"interval":1001}
Next: {"value":1,"interval":999}
Next: {"value":2,"interval":1000}
As mentioned in the pausable documentation, pausable is to be used on hot sources.
One way to make a source hot is to use share. However, this will not work as is in conjunction with pausable because share will disconnect its source when it has no subscribers, which will happen when you will pause.
So here are two ways to make this work. One is to use share and keep a dummy subscriber so that share never disconnects from its source as there will always be at least one subscriber. The second way is to use publish, and connect the observable once all the wiring has been made.
Example 1 with dummy subscriber:
var pauser = new Rx.Subject();
function noop(){}
var source = Rx.Observable
.interval(1000)
.timeInterval()
.share();
var pausableSource = source.pausable(pauser);
var subscription = pausableSource.subscribe(
function (x) {
$("#ta_result").append('Next: ' + JSON.stringify(x) + '<br>');
},
function (err) {
$("#ta_result").append('Error: ' + err);
},
function () {
$("#ta_result").append('Completed');
});
source.subscribe(noop);
pauser.onNext(false);
var paused = false;
$("#result").click(function() {
$("#ta_change").append("mouse clicked\n");
paused = !paused;
pauser.onNext(paused);
});
Example 2 with connect:
var pauser = new Rx.Subject();
var source = Rx.Observable
.interval(1000)
.timeInterval()
.publish();
var pausableSource = source.pausable(pauser);
// source.subscribe(function(){});
var subscription = pausableSource.subscribe(
function (x) {
$("#ta_result").append('Next: ' + JSON.stringify(x) + '<br>');
},
function (err) {
$("#ta_result").append('Error: ' + err);
},
function () {
$("#ta_result").append('Completed');
});
source.connect();
pauser.onNext(false);
var paused = false;
$("#result").click(function() {
$("#ta_change").append("mouse clicked\n");
paused = !paused;
pauser.onNext(paused);
});
I have been trying to wrap my head around jquery deferred and then functions. As I gather from jQuery then documentation, the then function sends the return value of the callback to the next then handler if they are so chained. Given that, why is my code not working as expected?
function log(message) {
var d = new Date();
$('#output').append('<div>' + d.getSeconds() + '.' + d.getMilliseconds() + ': ' + message + '</div>');
}
function asyncWait(millis) {
var dfd = $.Deferred();
setTimeout(function () {
var d = new Date();
log('done waiting for ' + millis + 'ms');
dfd.resolve(millis);
}, millis);
return dfd.promise();
}
function startTest0() {
return asyncWait(1000).then(asyncWait).then(asyncWait).then(asyncWait).done(function () {
log('all done, 4 times');
});
}
function startTest() {
asyncWait(500).then(function () {
return asyncwait(1000);
}).then(function () {
return asyncWait(1500);
}).then(function () {
return asyncWait(2000);
}).done(function () {
log('all done');
});
}
log('welcome');
log('starting test ...');
startTest0().done(function() { log('starting the second test'); startTest(); });
JS Fiddle here: Sample code. I was expecting a similar behavior in both tests but something eludes me. What am I missing?
Thanks in advance!
EDIT: See an updated DEMO where I am trying to chain the async operations to start after the previous one is done.
Except for one typo (asyncwait instead of asyncWait) your code works. Check below.
function log(message) {
var d = new Date();
$('#output').append('<div>' + d.getSeconds() + '.' + d.getMilliseconds() + ': ' + message + '</div>');
}
function asyncWait(millis) {
var dfd = $.Deferred();
setTimeout(function () {
var d = new Date();
log('done waiting for ' + millis + 'ms');
dfd.resolve(millis);
}, millis);
return dfd.promise();
}
function startTest0() {
return asyncWait(1000).then(asyncWait).then(asyncWait).then(asyncWait).done(function () {
log('all done, 4 times');
});
}
function startTest() {
asyncWait(500).then(function () {
return asyncWait(1000);
}).then(function () {
return asyncWait(1500);
}).then(function () {
return asyncWait(2000);
}).done(function () {
log('all done');
});
}
log('welcome');
log('starting test ...');
startTest0().done(function() { log('starting the second test'); startTest(); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
Lesson to learn: Put any JS code through jshint before and after you fix bugs.
As i can see here, you are calling startTest0 function returning its promise object and calling then callback without returning new times into next then callback. I modified your startTest() into this :
function startTest() {
return asyncWait(500).then(function () {
asyncWait(1000);
return 1500; // here we pass to the next then
}).then(function (ms) { // ms here we got 1500
asyncWait(ms);
return 2000; // here we pass to the next then
}).then(function (ms) { // ms here we got 2000
asyncWait(ms)
return asyncWait(2500);
}).done(function () {
log('all done');
});
}
DEMO
I'm trying to run through (using foreach) an array of objects and then for each I'd like to call a function that uses request to get a file and then unzips it with zlib, but one at a time, given the nature of node this is currently done asynchronously.
I'd like it to be done something like this...
- foreach - first object
- call function for first object
- when function has completed
- go to the next object in the array
I have tried using the SYNC module to try and solve this but with no luck.
Any ideas on how I can achieve this?
// the function i am trying to run for each in sync
var downloadUnzipFile = function(mID) {
try {
// Read File
console.log("Started download/unzip of merchant: " + mID + " # " + new Date().format('H:i:s').toString());
request(linkConst(mID))
// Un-Gzip
.pipe(zlib.createGunzip())
// Write File
.pipe(fs.createWriteStream(fileName(mID)))
.on('error', function(err) {
console.error(err);
})
.on('finish', function() {
console.log("CSV created: " + fileName(mID));
console.log("Completed merchant: " + mID + " # " + new Date().format('H:i:s').toString());
//console.log("Parsing CSV...");
//csvReader(fileName);
});
} catch (e) {
console.error(e);
}
}
module.exports = function(sMerchants) {
var oMerchants = JSON.parse(JSON.stringify(sMerchants));
sync(function() {
oMerchants.forEach(function eachMerchant(merchant) {
downloadUnzipFile(merchant.merchant_aw_id);
})
})
};
var promiseQueue = (function() {
'use strict';
var promiseQueue = function() {
var queue = [Promise.resolve(true)];
var add = function(cb) {
var args = Array.prototype.slice.call(arguments);
args.shift();
queue.unshift(new Promise(function(resolve) {
queue[0].then(function() {
resolve(cb.apply(null, args));
queue.pop();
});
}));
};
return {
add: add
}
}
return promiseQueue;
}());
usage EXAMPLE:
This is the asynch function that will be called
var theFun = function (time, n) { // use whatever arguments you like that will be called with your function
return new Promise(function(resolve) {
//asynch function goes here INSTEAD of the setTimeout and it's contents, I repeat, INSTEAD of the setTimeout
setTimeout(function() { // this is for demonstrating ONLY
console.log('resolving', n, time); // this is for demonstrating ONLY
resolve(time); // this is for demonstrating ONLY
}, time); // this is for demonstrating ONLY
// remember to resolve("someValueNotImportantAsItIsntUsedAnywhere") on completion of your asynch function
});
}
This is how the items get added to the queue - I did it this way because of MY use case
var pq = promiseQueue();
for(var i = 0; i < 5; i++ ) {
var r = 1000 - i * 150;
console.log('adding ', i, r);
pq.add(theFun, r, i);
}
Hope you find this of some use
First, your function needs to take a callback so it can communicate when it has finished:
var downloadUnzipFile = function(mID, next) {
try {
// Read File
console.log("Started download/unzip of merchant: " + mID + " # " + new Date().format('H:i:s').toString());
request(linkConst(mID))
// Un-Gzip
.pipe(zlib.createGunzip())
// Write File
.pipe(fs.createWriteStream(fileName(mID)))
.on('error', function(err) {
console.error(err);
})
.on('finish', function() {
console.log("CSV created: " + fileName(mID));
console.log("Completed merchant: " + mID + " # " + new Date().format('H:i:s').toString());
//console.log("Parsing CSV...");
//csvReader(fileName);
next();
});
} catch (e) {
console.error(e);
next();
}
}
Then, we need to recursively call each one when the previous has finished:
module.exports = function(sMerchants, next) {
var oMerchants = JSON.parse(JSON.stringify(sMerchants));
var i = 0;
var run = function() {
if(i < oMerchants.length)
downloadUnzipFile(i++, run);
else
next();
};
};
Note that I also added a callback to the exported function, so it can communicate when it is finished. If this is unnecessary, you can drop it.
This may work for you, uses Promise. Need to add resolve and reject callbacks to your downloadUnzipFile-
var exports = (function () {
'use strict';
var pre = document.getElementById('out');
function log(str) {
pre.appendChild(document.createTextNode(str + '\n'));
}
function downloadUnzipFile(id, resolve, reject) {
log('Start: ' + id);
try {
setTimeout(function () {
resolve(id);
}, 3000);
} catch (e) {
reject(e);
}
}
function done(id) {
log('Done: ' + id);
}
function error(e) {
log(e.message);
}
function getPromise(mID) {
return new Promise(function (resolve, reject) {
downloadUnzipFile(mID, resolve, reject);
});
}
return function (sMerchants) {
JSON.parse(sMerchants).reduce(function (next, mID) {
if (!next) {
next = getPromise(mID);
} else {
next = next.then(function (id) {
done(id);
return getPromise(mID);
}, error);
}
return next;
}, null).then(done, error);
};
}());
exports(JSON.stringify([1, 2, 3, 4, 5]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/json2/20150503/json2.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.1.7/es5-shim.min.js"></script>
<script src="https://rawgit.com/jakearchibald/es6-promise/master/dist/es6-promise.min.js"></script>
<pre id="out"></pre>
I added the browser shims to support older browsers that may be viewing this, you shouldn't need them on node.js but you may need to require a Promise shim if you are using an old node.js.
I have written a function , which is returning a value. In my main i am calling the function like this:
var fn_return_val = lesson.select_lesson(lesson1_text);
console.log("returned value is : " + fn_return_val);
And my function implementation is like(other file.js) :
module.exports = {
select_lesson:
function select_lesson(lesson_name) {
console.log('\n ************************* Lessson name: ' + lesson_name);
var desiredOption, status;
var repeter = element.all(by.repeater('item in items'));
repeter.then(function (items) {
items.forEach(function (icon) {
console.log('\n ************************* item');
icon.getText().then(function (txt) {
if (txt == lesson_name) {
desiredOption = icon;
}
})
}).then(function clickOption() {
if (desiredOption) {
var el = desiredOption.all(by.css('[ng-click="launchActivity()"]'));
var el_progress = desiredOption.all(by.css('.pna-progress'));
var abc = el.getAttribute('value').then(function (txt) {
status = txt;
return status
});
el_progress.getAttribute('style').then(function (progress) {
console.log('\n ************************* Lessson progress : ' + progress);
});
el.click();
}
});
});
}
};
The problem is function is returning "undefined" value, and the print statement console.log("returned value is : " + fn_return_val);
is executing before the function implementation
Can anyone help me on resolving this?
This is all about promises and protractor's Control Flow.
You need to resolve the promise and log the results inside then:
lesson.select_lesson(lesson1_text).then(function(fn_return_val) {
console.log("returned value is : " + fn_return_val);
});
And you also need to return from a function:
function select_lesson(lesson_name) {
...
// return here
return repeter.then(function (items) {
...
}).then(function clickOption() {
...
});
});
}