This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 4 years ago.
Node.js code to extract all the links from the web page and store it in the variable that stores the data inside the scope of the function but not showing the data outside the scope of the function.
var ineed = require('ineed');
var url = require('get-urls');
var list = require('collections/list');
var fs = require('fs');
var arr = [];
ineed.collect.hyperlinks.from("https://energy.economictimes.indiatimes.com/rss/", function (err, response, result) {
var links = url(JSON.stringify(result)).toArray();
var str="/rss/";
for(var i = 0; i<links.length; i++){
if((links[i].search(str))>-1){
arr.push(links[i]);
}
}
console.log(arr);
// I am getting the output of the array here
})
//While printing the array I am not getting the output
console.log(arr);
You got noting in second console.log just because your code wich collect information run asynchronously and arr accepted any value after the first console.log executed. So either you rewrite your code on "clean" promises like
new Promise((resolve)=>ineed.collect.hyperlinks.from(
"https://energy.economictimes.indiatimes.com/rss/",
function (err, response, result) {
var links = url(JSON.stringify(result)).toArray();
var str="/rss/";
for(var i = 0; i<links.length; i++){
if((links[i].search(str))>-1){
arr.push(links[i]);
}
}
resolve(arr)
}
))
.then((arr)=>console.log(arr));
or convert to async/await function.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I am writing a steam bot and am trying to check, if one of the items in a trade is worth below 1 USD. I need to access the "pass" variable, but it never works. Can someone help?
var receive = offer.itemsToReceive;
var pass = true;
receive.forEach(function(id) {
var args = id.split(",");
market.getItemPrice("some app id", some item name).then(function(result) {
var json = JSON.parse(JSON.stringify(result)); // returns e.G $0.08
var price = parseFloat(json.median_price.substring(1));
if(price*100 < 100) {
pass = false;
}
});
});
This question is asked a lot, but hopefully explaining it in your own problem's terms will help you understand.
Your code should wait for any possibility of pass = false;, but it doesn't because you call a asynchronous function --- imagine the code immediately moves on after calling that. Your foreach function is immediately processed and the next line is called until .getItemPrice responds some time later.
So instead, to "wait" for all the results, you can do something like:
var receive = offer.itemsToReceive;
var pass = true;
var itemReceivePromises = receive.map(id=>{
var args = id.split(",");
return market.getItemPrice("some app id", some item name).then(function(result) {
var json = JSON.parse(JSON.stringify(result)); // returns e.G $0.08
var price = parseFloat(json.median_price.substring(1));
if(price*100 < 100) {
pass = false;
}
});
});
Promise.all(itemRecievePromises).then(results=>{
console.log('pass',pass);
});
However, you should pass the "pass" result back through the promise instead of using a higher scoped variable.
I have this below code, but as soon as widgetsAddCall is added into array, it gets executed, and promise.each is of no use.
Function widgetsAddCall is making async request to API server and returns bluebird promisified request. I want that API call is made one after another, so that each call sends chunk of data one after another.
var chunkCnt = Math.ceil(widgetsIds.length/4000);
var responseT = Array();
var Promise = require('bluebird');
for(var cntTemp =0 ; cntTemp<chunkCnt;cntTemp++){
var tempWidgs = widgetsIds.slice(cntTemp,cntTemp+4000);
var query = {
id: tempWidgs.join(',')
};
responseT.push(widgetsAddCall(tempWidgs,query,campRemoteId,campaign));
}
return Promise.each(responseT,function(responses) {
// Use the responses here
return getWidgets(campRemoteId,campaign).then((ids) => {
var toRemove = [];
for(var id of ids){
if(widgetsIds.indexOf(id)===-1){
toRemove.push(id);
}
}
if(toRemove.length) {
return removeWidgets(campaign, campRemoteId, toRemove);
}
});
})
I want that API call is made one after another, so that each call
sends chunk of data one after another.
The simplest way I can think of to serialize all your calls is to prebuild your chunks into an array and then use Bluebird's Promise.mapSeries() to serially iterate through the array:
var Promise = require('bluebird');
// pre-build chunks into an array
var chunks = [];
var chunkCnt = Math.ceil(widgetsIds.length / 4000);
for (var chunkIndex = 0; chunkIndex < chunkCnt; chunkIndex++) {
chunks.push(widgetsIds.slice(cntIndex,cntIndex + 4000));
}
// now serially iterate the array
Promise.mapSeries(chunks, function(item) {
return widgetsAddCall(item, {id: item.join(',')}, campRemoteId, campaign);
}).then(function(results) {
// now process the results of widgetsAddCall() here
});
FYI, your original use of Promise.each() was not making any sense to me because you were iterating an array of promises, but then not using any info from the iteration. There seemed to be no point to the iteration. Plus, you weren't properly serializing your calls to widgetsAddCall() anyway since you were launching all those calls in parallel.
I am trying to write a nodejs program. I have a file data.json , it contains json objects. For every object i have to add another key as review ,value as a text file data. here , I wrote code for reading data from json file, in that file , for every object I inserted key and value pairs. and stored in a array named 'matter', In below code, I used callback to post data to calling function. but callback is executing before 'for loop' in Fetchdata function. How to call callback after for loop.
var fs = require('fs');
var jf = require('jsonfile')
var file = '../data/data.json'
function readfile(str,callback) {
fs.readFile(str, function (err, data) {
callback && callback(data.toString());
});
}
function Fetchdata(callback) {
var matter = [];
jf.readFile(file, function (err, jsonData) {
var j=0;
for (var i = 0; i < jsonData.length; ++i) {
obj = jsonData[i];
var purchase_url = obj["purchase_url"];
if (purchase_url.indexOf("flipkart") > -1) {
var ss = purchase_url.split("pid=");
if (ss[1]) {
var s2 = ss[1].split('&');
readfile(s2[0],function(some){
"use strict";
obj["review"]= some;
matter.push(obj);
})
}
}
}
callback && callback(matter);
});
}
Fetchdata(function (some) {
console.log(some[0]);
});
You can use sync version of readFile
function readfile(filename,callback) {
callback(fs.readFileSync(filename).toString())
}
The sync version of readFile, will not continue to the next line. It will return the content of the file.
You can also, do it in one line fs.readFileSync(str,'utf-8') instead of using toString.
More info
readFileSync API
Synchronous vs Asynchronous code with Node.js
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I need to mention that I'm new to Node.js in general but I'm not sure why for the following code will give me different outputs in console for questions and allQuestions variable ?
var models = require('./models')(mongoose);
var query = models.Question.find({});
var questions = Array();
query.exec(function(err, allQuestions){
//catch the error;
questions = allQuestions;
console.log(allQuestions);
});
console.log(questions);
Output of questions variable will be only: Mongoose: questions.find({}) { fields: undefined } while allQuestions will contain all the questions from database.
I need to know why ?
Also I need that my question variable contains allQuestions from database.
Thats because query.exec() runs the function you passed as parameter asynchronously and the last line console.log(questions); will be executed before the callback is.
If you need the value of questions, then use another callback:
var models = require('./models')(mongoose);
var query = models.Question.find({});
var questions = Array();
query.exec(function(err, allQuestions){
//catch the error;
questions = allQuestions;
console.log(allQuestions);
done();
});
function done() {
console.log(questions);
// handle `questions` here ...
}
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I am a beginner to node.js. I was trying out the examples from the 'learnyounode' tutorial. I am trying to write a program that takes three url parameters and fetches some data from those urls and displays the returned data in the order in which the urls were provided.
var http = require('http');
var bl = require('bl');
var url = [];
url[0] = process.argv[2];
url[1] = process.argv[3];
url[2] = process.argv[4];
var data = [];
var remaining = url.length;
for(var i = 0; i < url.length; i++){
http.get(url[i], function (response){
response.setEncoding('utf8');
response.pipe(bl(function (err, chunk){
if(err){
console.log(err);
}
else{
data[i] = chunk.toString();
console.log(data[i]);
remaining -= 1;
if(remaining == 0) {
for(var j = 0; j < url.length; j++){
console.log(data[j]);
}
}
}
}));
});
}
I have two console.log statements in the program. The output i get is as follows:
It'll be chunder where lets throw a ford. We're going durry where mad as a cooee
.
Shazza got us some apples with come a strides. Mad as a swag when get a dog up y
a roo. It'll be rapt piece of piss as cunning as a trackie dacks.
As cross as a bogged with watch out for the boardies. As cunning as a digger fla
min lets get some roo bar. As dry as a piker piece of piss he hasn't got a joey.
Lets throw a strides mate we're going digger.
undefined
undefined
undefined
It seems like the data is correctly fetched and stored in the 'data' array but it still displays undefined.
Any idea why this is happening?
Thanks in advance!
This is a very common issue in async programming in node.js or even in the browser. A main issue you have is that the loop variable i will not be what you want it to be some time later when the async callback is called. By then, the for loop will have run to the end of its loop and i will be at the end value for all response callbacks.
There are numerous ways to solve this. You can use a closure to close over the i value and make it uniquely available to each callback.
var http = require('http');
var bl = require('bl');
var url = [];
url[0] = process.argv[2];
url[1] = process.argv[3];
url[2] = process.argv[4];
var data = [];
var remaining = url.length;
for(var i = 0; i < url.length; i++){
// create closure here to uniquely capture the loop index
// for each separate http request
(function(index) {
http.get(url[index], function (response){
response.setEncoding('utf8');
response.pipe(bl(function (err, chunk){
if(err){
console.log(err);
}
else{
data[index] = chunk.toString();
console.log(data[index]);
remaining -= 1;
if(remaining == 0) {
for(var j = 0; j < url.length; j++){
console.log(data[j]);
}
}
}
}));
});
})(i);
}
If you do much node.js programming, you will find that you probably want to learn how to use promises because they are very, very handy for controlling the flow and sequence of async operations.