foreach的异步(async,await)的问题及其处理方式

开发中遇见个难题很苦恼,好在我解决了,只要能解决我就很开心😄😄😄

本篇文章从forEach方法 到promise 到async await统统理解个遍,进入正题

 

先看下面代码会出现什么问题:

     const arr = [1,2,3,4,5,6];
        const result = [];
        const fn = (item) => {
            let time = Math.ceil(Math.random()*1000)
            return new Promise(resolve => {
                setTimeout(() => {
                    resolve(item)
                }, time);
            })
        }
        arr.forEach(async (item) => {
            const val = await fn(item);
            result.push(val);
            console.log(result);
        })
       

 输出结果顺序,看随机数的脸色。 可能是[6, 5, 4, 1, 3, 2] 或者 [3, 5, 4, 6, 1, 2] 或者等等。。。。。。。

 那么问题来了
 问题1: 我想在这个forEach执行完之后怎么按arr的顺序得到结果
 问题2: 怎么等所有异步执行完成拿到result,再执行以后的代码。
 今天就伴随这俩问题我们开始整
        const result1 = [];
        (async()=>{
            for(let i = 0; i < arr.length; i++){
                const val1 = await fn(arr[i]);
                result1.push(val1);
            }
            //在这里拿到执行结果result,再执行依赖result的代码
            console.log(result1);
        })();    

 这个结果妥妥的解决了,得到的顺序是 [1, 2, 3, 4, 5, 6],知道为啥吗?你要知道那你可以走了 拜拜👋

 接着来, 我们不是未来解决问题而解决问题。接下来就要搞清楚forEach为啥不行
 
 看下forEach的实现源码:
 
     // Production steps of ECMA-262, Edition 5, 15.4.4.18
        // Reference: http://es5.github.io/#x15.4.4.18
        if (!Array.prototype.forEach) {

        Array.prototype.forEach = function(callback, thisArg) {

            var T, k;

            if (this == null) {
            throw new TypeError(' this is null or not defined');
            }

            // 1. Let O be the result of calling toObject() passing the
            // |this| value as the argument.
            var O = Object(this);

            // 2. Let lenValue be the result of calling the Get() internal
            // method of O with the argument "length".
            // 3. Let len be toUint32(lenValue).
            var len = O.length >>> 0;

            // 4. If isCallable(callback) is false, throw a TypeError exception.
            // See: http://es5.github.com/#x9.11
            if (typeof callback !== "function") {
            throw new TypeError(callback + ' is not a function');
            }

            // 5. If thisArg was supplied, let T be thisArg; else let
            // T be undefined.
            if (arguments.length > 1) {
            T = thisArg;
            }

            // 6. Let k be 0
            k = 0;

            // 7. Repeat, while k < len
            while (k < len) {

            var kValue;

            // a. Let Pk be ToString(k).
            //    This is implicit for LHS operands of the in operator
            // b. Let kPresent be the result of calling the HasProperty
            //    internal method of O with argument Pk.
            //    This step can be combined with c
            // c. If kPresent is true, then
            if (k in O) {

                // i. Let kValue be the result of calling the Get internal
                // method of O with argument Pk.
                kValue = O[k];

                // ii. Call the Call internal method of callback with T as
                // the this value and argument list containing kValue, k, and O.
                callback.call(T, kValue, k, O);
            }
            // d. Increase k by 1.
            k++;
            }
            // 8. return undefined
        };
        }

 

看完你会发现:

forEach每次执行都会执行一个回调函数,是不是听不大明白,举个例子
            async function fn2 (){
                let val2 = await fn(1);
                console.log(val2)
            };
            
            async function fn3 (){
                let val3 = await fn(2);
                console.log(val3)
            };
            fn2();
            fn3();        
forEach的回调函数就好比这样,这个很容易看懂fn2和fn3肯不是同步关系,要想同步必须在一个函数。
 
至此已经结束了。当然还有其他解决方案 有时间接着整理

 

 

  

posted @ 2021-12-20 16:18  zshNo1  阅读(1136)  评论(5编辑  收藏  举报