Reputation: 380
I still struggle with understanding how the steps are run.
Basically i am doing a foreach computing color then insert it in a database with normal foreach code :
var mysql = require("mysql"),
namer = require('color-namer'),
async = require('async');
var connection = mysql.createConnection({
multipleStatements: true,
host : 'localhost',
user : 'root',
password : 'root',
database : 'xxxx'});
connection.connect();
connection.query(
`SELECT color from sg_fashion_colors limit 10`,
function(err, results, fields) {
results.forEach(function(elem){
var currentHex = elem['color'],
currentColor = namer(currentHex);
console.log(currentHex);
connection.query(
`INSERT INTO name_color_pat_test (hex, basic) VALUES (?,?);`,
[currentHex,currentColor['basic'][0]['name']] ,
function(err,data){
console.log("insert");
}
);
});
}
);
but instead of doing
color
insert
color
insert
It does
color
color
insert
insert
I just don't understand the mechanism on why it will first foreach on the color then foreach on the insert.
For information i was able to produce the expected output that i want using async
connection.query(
`SELECT color from sg_fashion_colors limit 10`,
function(err, results, fields) {
async.eachSeries(results, function (elem, seriesCallback) {
var currentHex = elem['color'],
currentColor = namer(currentHex);
console.log(currentHex);
connection.query( `INSERT INTO name_color_pat_test (hex, basic) VALUES (?,?);`, // insert the SKU inside a database with their primary color
[currentHex,currentColor['basic'][0]['name']] ,
function(err, results, fields) {
if (err) throw err;
console.log("insert");
seriesCallback(null);
});
}, function(responsetoendofloop){
console.log("everything has run");
});
}
);
Upvotes: 0
Views: 215
Reputation: 30410
Let me just show another simplified case here:
var colors = ['blue', 'red', 'green'];
colors.forEach(function(color) {
console.log('before setTimeout', color);
setTimeout(function () {
console.log('after setTimeout', color);
}, 0);
});
If I try it in the Chrome console here's the output:
VM1119:3 before setTimeout blue
VM1119:3 before setTimeout red
VM1119:3 before setTimeout green
<- undefined
VM1119:5 after setTimeout blue
VM1119:5 after setTimeout red
VM1119:5 after setTimeout green
Same thing that happened in your script. setTimeout is similar to connection.query
as they both call their callback asynchronously, which means they will only do it when the current stack has finished executing and they will call the callback function. So in both cases the forEach continues to loop and once done then the callbacks are executed in order they were scheduled. Note the the undefined
is printed there when colors.forEach
is finished executing and it represents the return
value of the function. Try changing it to colors.map
instead.
Let me give you another example:
setTimeout(function () { console.log('hello'); }, 0)
while (true) {};
As you see the setTimeout is before the infinite while loop and it is meant to be executed immediately(0
milliseconds after), but it will never execute. When the javascript VM reads the first line, it will schedule the callback to be called later, then it will read the second line and it will get stuck there. setTimeout callback will never be called till the everything else in the stack has finished executing.
Now same thing happens for connection.query
. It's callback is scheduled to be called later. It also might take a dozen miliseconds or more(depending on the network and database) to be called. So by the time that it's called everything else is already have executed.
Now async.eachSeries
doesn't iterate like the forEach
. It waits till it's callback is called, not matter how long it takes.
So if you call callback outside of the connection.query
callback then probably might get the same results as the forEach
(this is bad code, don't change your code, it's just for your education):
async.eachSeries(results, function (elem, seriesCallback) {
var currentHex = elem['color'],
currentColor = namer(currentHex);
console.log(currentHex);
connection.query( `INSERT INTO name_color_pat_test (hex, basic) VALUES (?,?);`, // insert the SKU inside a database with their primary color
[currentHex,currentColor['basic'][0]['name']] ,
function(err, results, fields) {
if (err) throw err;
console.log("insert");
});
seriesCallback(null);
});
This happens because now seriesCallback
before connection.query
result is ready, even though it's placed after it.
Feel free to ask more questions in the comments if still not clear.
Upvotes: 1