Confusion using Observable.switch - rxjs5

The switch documentation on github contains an example on how to use the command.
var source = Rx.Observable.range(0, 3)
.select(function (x) { return Rx.Observable.range(x, 3); })
.switch();
var subscription = source.subscribe(
function (x) {
console.log('Next: ' + x);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});
I've tested the code at stackblitz but the output differs. Instead of
Next: 0
Next: 1
Next: 2
Next: 3
Next: 4
Completed
the console logs
Next: 0
Next: 1
Next: 2
Next: 1
Next: 2
Next: 3
Next: 2
Next: 3
Next: 4
Completed
Can somebody explain?

Now I got it. The difference in the output comes from the fact that each inner observable sequence (created by the second call to range) won't be canceled as specified by the switch-operator since each observable sequence is emitted before the next sequence has been received, i.e. the observables in that sequence complete before switch has the chance to cancel those. But if I delay the emission only the elements of the
most recent inner observable sequence
is logged to the console:
var source = Rx.Observable
.range(0, 3)
.map(x => Rx.Observable.range(x, 3).delay(1))
.switch();
var subscription = source.subscribe(
function (x) {
console.log('Next: ' + x);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});
Output:
Next: 2
Next: 3
Next: 4
Completed

Related

NextJS API Route Returns Before Data Received?

I'm not sure what's going on here. I have set up an API route in NextJS that returns before the data has been loaded. Can anyone point out any error here please?
I have this function that calls the data from makeRequest():
export async function getVendors() {
const vendors = await makeRequest(`Vendor.json`);
console.log({ vendors });
return vendors;
}
Then the route: /api/vendors.js
export default async (req, res) => {
const response = await getVendors();
return res.json(response);
};
And this is the makeRequest function:
const makeRequest = async (url) => {
// Get Auth Header
const axiosConfig = await getHeader();
// Intercept Rate Limited API Errors & Retry
api.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
await new Promise(function (res) {
setTimeout(function () {
res();
}, 2000);
});
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
token[n] = null;
originalRequest._retry = true;
const refreshedHeader = await getHeader();
api.defaults.headers = refreshedHeader;
originalRequest.headers = refreshedHeader;
return Promise.resolve(api(originalRequest));
}
return Promise.reject(error);
}
);
// Call paginated API and return number of requests needed.
const getQueryCount = await api.get(url, axiosConfig).catch((error) => {
throw error;
});
const totalItems = parseInt(getQueryCount.data['#attributes'].count);
const queriesNeeded = Math.ceil(totalItems / 100);
// Loop through paginated API and push data to dataToReturn
const dataToReturn = [];
for (let i = 0; i < queriesNeeded; i++) {
setTimeout(async () => {
try {
const res = await api.get(`${url}?offset=${i * 100}`, axiosConfig);
console.log(`adding items ${i * 100} through ${(i + 1) * 100}`);
const { data } = res;
const arrayName = Object.keys(data)[1];
const selectedData = await data[arrayName];
selectedData.map((item) => {
dataToReturn.push(item);
});
if (i + 1 === queriesNeeded) {
console.log(dataToReturn);
return dataToReturn;
}
} catch (error) {
console.error(error);
}
}, 3000 * i);
}
};
The issue that I'm having is that getVendors() is returned before makeRequest() has finished getting the data.
Looks like your issue stems from your use of setTimeout. You're trying to return the data from inside the setTimeout call, and this won't work for a few reasons. So in this answer, I'll go over why I think it's not working as well as a potential solution for you.
setTimeout and the event loop
Take a look at this code snippet, what do you think will happen?
console.log('start')
setTimeout(() => console.log('timeout'), 1000)
console.log('end')
When you use setTimeout, the inner code is pulled out of the current event loop to run later. That's why end is logged before the timeout.
So when you use setTimeout to return the data, the function has already ended before the code inside the timeout even starts.
If you're new to the event loop, here's a really great talk: https://youtu.be/cCOL7MC4Pl0
returning inside setTimeout
However, there's another fundamental problem here. And it's that data returned inside of the setTimeout is the return value of the setTimeout function, not your parent function. Try running this, what do you think will happen?
const foo = () => {
setTimeout(() => {
return 'foo timeout'
}, 1000)
}
const bar = () => {
setTimeout(() => {
return 'bar timeout'
}, 1000)
return 'bar'
}
console.log(foo())
console.log(bar())
This is a result of a) the event loop mentioned above, and b) inside of the setTimeout, you're creating a new function with a new scope.
The solution
If you really need the setTimeout at the end, use a Promise. With a Promise, you can use the resolve parameter to resolve the outer promise from within the setTimeout.
const foo = () => {
return new Promise((resolve) => {
setTimeout(() => resolve('foo'), 1000)
})
}
const wrapper = async () => {
const returnedValue = await foo()
console.log(returnedValue)
}
wrapper()
Quick note
Since you're calling the setTimeout inside of an async function, you will likely want to move the setTimeout into it's own function. Otherwise, you are returning a nested promise.
// don't do this
const foo = async () => {
return new Promise((resolve) => resolve(true))
}
// because then the result is a promise
const result = await foo()
const trueResult = await result()

rxjs takeuntil, check until observable source is valid

After searching for hours... most of example is like this...
var source = Rx.Observable.timer(0, 1000)
.takeUntil(Rx.Observable.timer(5000));
var subscription = source.subscribe(
function (x) { console.log('Next: ' + x); },
function (err) { console.log('Error: ' + err); },
function () { console.log('Completed'); })
Result
Next: 0
Next: 1
Next: 2
Next: 3
Next: 4
Completed
but, I wan to know is it possible to check from source value not another observable object.. something like this..
var source = Rx.Observable.timer(0, 1000)
.takeUntil((result) => result == 5);
I guess what you are looking for is takeWhile
var source = Rx.Observable.timer(0, 1000)
.takeWhile((result) => result < 5);
source.subscribe(
(val) => console.log(val),
(err) => console.log(err),
() => console.log('complete')
);

jQuery deferred promise progress notification

I've been playing with promises and trying to build some sort of progress notification.
The code is executing all functions in the right order, but the progress updates execute just before the resolve as opposed to when they actually happen.
Can anyone point out what I'm doing wrong?
function start(x) {
console.log("Start: " + x);
var promise = process(x);
console.log("promise returned");
promise.then(function(data) {
console.log("Completed: " + data);
}, function(data) {
console.log("Cancelled: " + data);
}, function(data) {
console.log("In Progress: " + data);
});
}
function process(x) {
var deferred = $.Deferred();
var promise = deferred.promise();
// process asynchronously
setTimeout(function() {
for (var i=0 ; i<x ; i++) {
sleep(1000);
deferred.notify(i);
}
if (x % 2 === 0) {
deferred.reject(x);
} else {
deferred.resolve(x);
}
}, 0);
return promise;
}
function sleep(sleepDuration) {
var now = new Date().getTime();
while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
}
start(3);
Fiddle here:
https://jsfiddle.net/n86mr9tL/
A delay timer implemented with while(), will "block" - ie hog the processor.
Blocking not only prevents other javascript from running but also inhibits reliable refreshing of the browser screen including the console. So whereas those deferred.notify(i) and console.log("In Progress: " + data) statements are firing, the console isn't refreshed until the processor becomes free to do so.
Unsurprisingly, the solution lies in not using while().
Fortunately, javascript imcludes two built-in methods window.setTimeout() and window.setInterval(), which are conceptually different from a while() idler but fulfil the same role .... without blocking.
window.setInterval(fn, t) fires function fn every t milliseconds,
window.setTimeout(fn, t) fires function fn once, after t milliseconds.
Both methods return an opaque reference, which allows them to be cancelled.
In the code below, start() is unmodified, process() is heavily modified and sleep() has disappeared.
process() now does the following :
creates a jQuery Deferred and returns a promise derived from it,
establises a setInterval() of 1000 milliseconds (1 second), whose function :
keeps count of how many times it has been called,
calls deferred.notify() every second until the counter i reaches the specified maximum x,
when the specified maximum is reached :
the interval, which would otherwise silently tick away ad infinitum, is cleared,
deferred.resolve() or deferred.reject() are called to settle the Deferred (and its promise),
function start(x) {
console.log("Start: " + x);
process(x).then(function(data) {
console.log("Completed: " + data);
}, function(data) {
console.log("Cancelled: " + data);
}, function(data) {
console.log("In Progress: " + data);
});
}
function process(x) {
return $.Deferred(function(dfd) {
var i = 1;
var intervalRef = setInterval(function() {
if(i < x) {
dfd.notify(i++);
} else {
clearInterval(intervalRef);
dfd[(x % 2 === 0)?'reject':'resolve'](x);
}
}, 1000);
}).promise();
}
console.clear();
start(3);
Updated fiddle

Rxjs 4 simple debug with console.log

I'm quite new at rxjs stuff so please be patience :).
var source = Rx.Observable.fromEvent(document, 'keyup');
source.filter(function(x){
console.log('filter with', x);
return true;
});
var subscription = source.subscribe(
function (x) {
console.log('Next: keyup!',x.keyCode);
},
function (err) {
console.log('Error: %s', err);
},
function () {
console.log('Completed');
});
whats the right way to debug inside filter
I dont see any filter with
in the console
I've also tried with
var source = Rx.Observable.fromEvent(document, 'keyup');
source.filter(function(x){
console.log('filter with', x);
return true;
});
source.do(x => console.log('do with',x));
var subscription = source.subscribe(
function (x) {
console.log('Next: keyup!',x.keyCode);
},
function (err) {
console.log('Error: %s', err);
},
function () {
console.log('Completed');
});
with no lucky
Can you give me an hint please ?
source.filter() is creating a new Observable, yet you only subscribe to the original Observable, source. Observables that aren't subscribed to are not carried out
You have to do something like this:
source.filter()
.do()
.subscribe()

Parse background job add multiple record stops after 21 records

I am trying to add multiple records via Parse background job. I am not getting any error it's just stop saving records after 21 records. Here's my code:
var _ = require('underscore');
Parse.Cloud.job('usagovJobsRunner', function (request, status) {
var promises = [];
for (var index = 0; index < 2; index++) {
promises.push(Parse.Cloud.httpRequest({
url: 'http://jobs.github.com/positions.json',
followRedirects: true,
params: {
page: index
}
}));
}
var jobs = [];
Parse.Promise.when(promises).then(function () {
console.log('arguments length: ' + arguments.length);
_.each(arguments, function (page) {
console.log('page lenght: ' + page.data.length);
_.each(page.data, function (job) {
var model = new (Parse.Object.extend('Jobs'));
model.set({
jobId: job.id,
title: job.title,
description: job.description,
location: job.location,
jobPosting: new Date(job.created_at),
type: job.type,
company: job.company,
companyUrl: job.company_url,
companyLogoUrl: job.company_logo,
source: 'Github Jobs',
jobUrl: job.url
});
jobs.push(model)
});
});
console.log('jobs count: ' + jobs.length);
Parse.Cloud.useMasterKey();
// save all the newly created objects
Parse.Object.saveAll(jobs, {
success: function (objs) {
// objects have been saved...
console.log('jobs saved.');
status.success('Github Jobs runner successfully loaded ' + objs.length + ' jobs');
},
error: function (error) {
// an error occurred...
console.log(error);
status.error('Error: ' + error);
}
});
status.success();
}, function (err) {
console.log(err);
status.error(err);
});
});
Here are my logs:
I2015-08-28T10:50:31.327Z]arguments length: 2
I2015-08-28T10:50:31.328Z]page lenght: 50
I2015-08-28T10:50:31.363Z]page lenght: 50
I2015-08-28T10:50:31.404Z]jobs count: 100
I2015-08-28T10:50:31.442Z]v15: Ran job usagovJobsRunner with: Input:
{} Result: undefined
Don't mix promises with traditional callbacks, choose one style and stick with it. Call status.success(); only once when everything is complete.
For calling to an arbitrary page depth you should create a plain JS function which takes a page number and returns a promise which is completed with the page data and page number. Now, you can call that function and when it's complete you can check if another page needs to be loaded and you also know what the page number is. When you get to the end you can call status.success()

Resources