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

  1. Callback A way of nesting asynchronous operations and calling back again
  2. Promise + then() layer by layer
  3. 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?