Ask questions
Question 1:
Let’s take a look at the code for loop, and let’s think about what the result is.
Var arr =,4,6,8,10 [2]; var arrLength = arr.length;for (var i = 0; i < arrLength; i++) {
setTimeout(function() {
console.log(i);
console.log(arr[i]);
}, 2000);
}
Copy the code
Question 2:
If multiple asynchronous functions occur in the for loop (such as Ajax requests, or node back-end operations that perform database or file operations), what should I do if I want these asynchronous serial operations to become synchronous?
Problem 1 solution and related explanation
The results of
The expected results
0, 2, 1, 4, 2, 6, 3, 8, 4, 10Copy the code
The result after running
5 undefined 5 undefined 5 undefined 5 undefined 5 undefined
Copy the code
The cause of the result
The setTimeout() callback is an asynchronous task, which appears in the macro task queue and is pushed to the end of the task queue. This code should be for loop until the synchronization task is completed, so the for loop increses I continuously during the loop and stops until I fails once, at which point I is 5. That’s five empty loops. The five setTimeouts declared during the for traversal are executed after setTimeOut has reached the predetermined time. Therefore, the result above will appear after the final run, which is not the expected result.
Note: For macro task queues, synchronization tasks and other related issues, if you have any questions, you can check out my other article for details.
Correctly executed solutions
1. Closure, execute function immediately
The first way to get the desired result is to use closures, which create a local scope inside the closure function. Each loop creates its own local scope, independent of changes in external variables. The code is as follows:
Var arr =,4,6,8,10 [2]; var arrLength = arr.length;for (var i = 0; i < arrLength; i++) {
(function(i) {
setTimeout(function() {
console.log('I was' + i);
console.log('the value is' + arr[i]);
}, 2000);
})(i);
}
Copy the code
2. let
Change the var in the code to let, which is good for the block-level scope inside the for loop. The for loop body in JS is special. Each execution is a new independent block scope. Variables declared with let will not change after being passed into the scope of the for loop body and will not be affected by the outside world.
The code is as follows:
Var arr =,4,6,8,10 [2]; var arrLength = arr.length; // I is declared in the global scope, but inforWhen used in the loop body local scope, variables are fixed without interference.for (let i = 0; i < arrLength; i++) {
(function(i) {
setTimeout(function() {
console.log('I was' + i);
console.log('the value is' + arr[i]);
}, 2000);
})(i);
}
Copy the code
Problem 2 solution and related explanation
Asynchronous for loops are common in node.js backend development or front-end Ajax requests. There are several solutions
- Callback A way of nesting asynchronous operations and calling back again
- Promise + then() layer by layer
- Async and await
Choose the best solution I personally think, 3async and await to explain.
Async + await
Example:
If you want to send a batch of data to the server, the next batch of data will not be sent until the previous batch is successfully sent (that is, the server returns a successful response), otherwise the sending will be terminated. This is a classic example of asynchronous interdependent operations in a for loop
Examples correspond to pseudocode:
async function task () {
for (letVal of [1, 2, 3, 4]) {// await the responselet result = await send(val);
if(! result) {break;
}
}
}
task();
Copy the code
With await in the pseudocode, we convert asynchro to asynchro, and only continue in the for loop when the next send request completes and the result is received.
Await:
- The line of statement executed with await is synchronous.
- After the async function is executed, it always returns a promise object, which can be understood as an asynchronous function (foreign). However, ———————- quotes a sentence in teacher Ruan Yifeng’s book:
When a function executes, it will return as soon as it encounters await, wait until the triggered asynchronous operation is complete, and then execute the following statement in the function body.
I to ruan yifeng teacher’s words to specify once again, may be some students are not special understanding. In fact, we call “await”, and the statement below “await” will not be executed. Instead, we return a promise object to the outer async function. The promise object behind “await” should also be resolved. “Await” is the line of code before it is truly finished. (Note: await should be the result of resolve and not a promise object after execution.)
Node.js backend development-await application in the for loop
Look at a piece of code applying await in a back-end project:
//dayResult is a queried arrayfor(const item of dayResult) {//TODO Queries the list of users whose VIP distance expireslet userIds=await db.vip.findAll({
where:{
experience_time:{
'$lte':moment().subtract(15-item.day,'day').endOf('day'),// get all four days before 0 minutes 0 seconds'$gte':moment().subtract(15-item.day,'day').startOf('day'}, vip_type:0}, attributes:['user_id',Sequelize.literal(`'${item.id}' as notice_id`)],
raw:true
});
userNoticeRecord=userNoticeRecord.concat(userIds)
}
Copy the code
conclusion
In the process of learning, think more, don’t just remember the result, think more about why? Hey, if you have any questions, please point out.
Welcome everyone to pay attention to my public number — programmer growth refers to north. Please search by yourself on wechat — “Programmer growth refers to north”
Previous Article: How to write an elegant SQL native statement?