d3.js v5 - Promise.all replaced d3.queue - d3.js

I've been using d3.js v4 for sometime now and I've learned that Mike Bostock has replaced the d3.queue in the v5 release with the Promise native JavaScript object. I would like to check with you if this code that I have written is properly queuing (asynchronously) these URL's:
var makeRequest = function() {
"use strict";
var bli = [
"http://stats.oecd.org/sdmx-json/data/BLI2013/all/all",
"http://stats.oecd.org/sdmx-json/data/BLI2014/all/all",
"http://stats.oecd.org/sdmx-json/data/BLI2015/all/all",
"http://stats.oecd.org/sdmx-json/data/BLI2016/all/all",
"http://stats.oecd.org/sdmx-json/data/BLI/all/all"
];
var promises = [];
bli.forEach(function(url) {
promises.push(
new Promise(function(resolve, reject) {
d3
.json(url)
.then(function(response) {
resolve(response);
})
.catch(function(error) {
console.log("Error on: " + url + ". Error: " + error);
reject(error);
});
})
);
});
Promise.all(promises).then(function(values) {
console.log(values);
});
};
makeRequest();
The code seems to function properly, but, is this proper code or is there a better way (a best practice approach) for queuing with Promise.all and d3.js? Is the catch error properly implemented?

You can simplify that code a lot: you don't net to use new Promise with d3.json, since d3.json will itself create the promise.
So, you can just do:
var files = ["data1.json", "data2.json", "data3.json"];
var promises = [];
files.forEach(function(url) {
promises.push(d3.json(url))
});
Promise.all(promises).then(function(values) {
console.log(values)
});
Or, if you're into the code golf, even shorter:
var files = ["data1.json", "data2.json", "data3.json"];
Promise.all(files.map(url => d3.json(url))).then(function(values) {
console.log(values)
});
Since I cannot use JSON files in the S.O. snippet, check the console in this bl.ocks: https://bl.ocks.org/GerardoFurtado/f08993c9c729b0b3452ef1803ad9dcbf/c4b45c5acce6033085a667cbb7d34203d15de0f0

Here's an approach with ES6 async functions and ES6 array destructuring:
async function chart() {
const [first, second] = await Promise.all([
d3.json('data1.json'),
d3.json('data2.json'),
])
console.log('data2.json :', second)
}
chart()

You can also add a formatting function for your data as such if you want to clean up your data to your preference.
.then() will have your data in a nice array which you can use later.
const myData = d3.csv("data.csv", formatterFunction)
.then(data => /* do whatever*/ )
function formatterFunction(row){
// do formatting
return // formatted data
}

Related

Upgrading Cloud function from Parse-server 2.0 to 3.0

I am in the middle of upgrading my Parse-server 2.0 Cloud functions to 3.0.
One of the functions working in 2.0 is:
Parse.Cloud.define("countOfObservations", function(request, response) {
var query = new Parse.Query("GCUR_OBSERVATION");
query.count({
success: function(count) {
// The count request succeeded. Show the count
response.success(count);
},
error: function(error) {
response.error("GCUR_OBSERVATION table lookup failed");
}
});
});
As the Parse-server 3.0 has removed response and leveraged native promises or async/await for asynchronous validation. I tried to rewrite the function as below.
Parse.Cloud.define("countOfObservations", (request) => {
var query = new Parse.Query("GCUR_OBSERVATION");
var countOfObs = 0;
query.count({ useMasterKey: true }).then( (count) => {
countOfObs = count;
console.log("*** count=" + countOfObs);
return new Promise(function(resolve, reject) {
if (countOfObs >= 0)
return resolve(countOfObs);
else
return reject();
})
});
});
When I called the function from client, it returned {} instead of {"result":2882} that I'd expected. However, the console did print *** count=2882.
How can I make the function work again using native promises?
The reason it returns an empty object is because your function does not wait for query.count to complete and immediately returns with undefined.
You can write return await query.count(...).then(...); or even better, transform the whole function into Promise syntax and save some code lines. The Parse Team has developed a helpful migration guide with examples to make the transition easier for you.
Then this would be all you need:
Parse.Cloud.define("countOfObservations", async (request) => {
const query = new Parse.Query("GCUR_OBSERVATION");
const count = await query.count({ useMasterKey: true });
console.log("*** count=" + count);
return {"count": count};
// or if you really need to reject:
// return count >= 0 ? Promise.resolve(count) : Promise.reject();
});

Jasmine - Multiple it's, one asynchronous call

Scenario
I'm trying to do multiple it specs on a single external load rather than have the external data loaded EVERY time.
Question
How can I do this with a single call of getExternalValue while still keeping my it definitions?
Ideas
Currently I'm doing all the expects in a single it block. I've also thought about storing the loaded value before my tests but then I'd have to find another way to make jasmine wait until the value is loaded.
Code
function getExternalValue(callback) {
console.log("getting external value");
setTimeout(function() {
callback(true);
}, 2000);
return false;
}
describe("mjaTestLambda()", function() {
it("is truthy", function(done) {
let truthy;
truthy = getExternalValue(function(bool) {
truthy = bool;
expect(truthy).toBeTruthy();
done();
});
});
it("is falsy", function(done) {
let truthy;
truthy = getExternalValue(function(bool) {
truthy = bool;
expect(!truthy).toBeFalsy();
done();
});
});
});
How can I do this with a single call of getExternalValue while still
keeping my it definitions?
Use beforeEach() or beforeAll() to get the resolved value. Personally I suggest beforeEach() as it will reset the value for each test and helps ensure a clean setup for each one.
I noticed your function has a callback parameter. Async/await is a useful pattern that works best when (1) you're writing async/await functions or (2) your functions return a Promise. If you need to keep the callback parameter, let me know and I'll update the following:
// returns Promise
function getExternalValue() {
return new Promise((resolve, reject) => {
console.log("getting external value");
setTimeout(() => {
resolve(true);
}, 2000);
});
}
describe("mjaTestLambda()", () => {
let value;
beforeAll(() => {
return getExternalValue()
.then((v) => { value = v; });
});
it("is truthy", () => {
expect(v).toBeTruthy();
});
it("is not falsy", () => {
expect(!v).toBeFalsy();
});
});

Nativescript - Pass array from home-view-model to home.js

I´m having a hard time understanding how to perform this action(as the title says), and maybe someone could help me understand the process, my code is below:
My home-view-model:
var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;
var http = require("http");
function createViewModel() {
http.getJSON("http://myJsonfile").then(function (r) {
var arrNoticias = new ObservableArray(r.data);
return arrNoticias;
}, function (e) {
});
}
exports.createViewModel = createViewModel;
I have done a console.log of the arrNoticias before i have putted it inside a callback function and it returns [object object] etc...and then i have done this:
console.log(arrNoticias.getItem(0).titulo);
and it returns the info i need!.
Then in my home.js file i have this:
var observableModule = require("data/observable")
var ObservableArray = require("data/observable-array").ObservableArray;
var arrNoticias = require('./home-view-model.js');
console.log(arrNoticias.getItem(0).titulo);
and the result in the console is:
TypeError: arrNoticias.getItem is not a function. (In 'arrNoticias.getItem(0)', 'arrNoticias.getItem' is undefined)
My question is, how does this action is perform? passing the data from view-model to the .js file?
Thanks for your time
Regards
As that function send a URL request so probably it's an async function, which is on hold while requesting so that's why you get undefined. Normally, you will want your function that sends a URL request to return a promise. Based on that promise, you will the result as expected after the request is done. So:
function createViewModel() {
return new Promise<>((resolve, reject) => {
http.getJSON("http://myJsonfile").then(function (r) {
var arrNoticias = new ObservableArray(r.data);
resolve(arrNoticias);
}, function(e) {
reject(e);
});
}), (e) => {
console.log(e);
})
}
In home.js:
var homeVM= require('./home-view-model.js');
var arrNoticias;
homeVM.createViewModel().then(function(r) {
arrNoticias = r;
});

SailsJS how to correct this promise issue?

I use sails.js to update stock data from difference variable. When I do, console.log(product.stock), the value is 4. But it seems product.save() function below is not executed because attribute stock still not changed to 4. I guess the problem is at promise. Anybody know how to fix this?
exports.updateProductStock = function (details) {
details.forEach(function( detail ) {
var findPrevDetailRule = {
invoice: detail.invoice,
product: detail.product.id
};
var createPrevDetailRule = {
invoice: detail.invoice,
product: detail.product.id,
quantity: detail.quantity
};
var requirementBeforeUpdateStock = [
PreviousDetail.findOne(findPrevDetailRule).sort('createdAt desc').then(),
PreviousDetail.create(createPrevDetailRule).then()
];
Q.all(requirementBeforeUpdateStock)
.spread(function( prevDetail, newPrevDetail ) {
var difference = detail.quantity - prevDetail.quantity;
return {
prevDetail: prevDetail,
difference: difference
};
})
.then(function( results ) {
Product.findOne(results.prevDetail.product).then(function(product) {
product.stock += results.difference;
// maybe this below is not execute
product.save();
console.log(product.stock);
});
})
});
Note: I use sails 0.10-rc8. Have tested with sails-mysql, sails-mongo, sails-postgres, but still same.
.save() accepts a callback with which you can report success/failure.
For example, you can repost back to the client (from the sails documentation) :
product.save(function (err) {
if (err) return res.send(err, 500);
res.json(product);
});
Depending on scope, you may need to pass res into your function
Alternatively, monitor success/failure in the console, eg ,
product.save(function (err) {
if (err) console.log('save error: ' + err);//assuming err to be a string
console.log('save success');
});
Should at least give you a clue as to what's going wrong.

Node JS - get file via AJAX and then use the data

How do I do this asynchronously?
var getData, myFunc;
getData = function() {
var data = "";
$.get("http://somewhere.com/data.xml", function(d) {
data = $("#selector", d).html();
});
return data; // does not work, because async callback not yet fired
};
myFunc = function() {
var data = getData();
// do something with data here
};
I am happy to completely re-factor to achieve what I want. I am just don't know what design pattern achieves this.
Well, you can't. You can return a promise though:
var getData, myFunc;
getData = function () {
var d = $.Deferred();
$.get("http://somewhere.com/data.xml", function (data) {
d.resolve($("#selector", data).html())
});
return d.promise();
};
getData().then(function (data) {
alert(data);
});
demo http://jsfiddle.net/W75Kt/2/

Resources