91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JS異步遍歷如何實現

發布時間:2023-05-05 17:05:13 來源:億速云 閱讀:71 作者:iii 欄目:開發技術

今天小編給大家分享一下JS異步遍歷如何實現的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    背景:需要給對象數組的每一項添加某個屬性,屬性值來源于接口(即需要遍歷數組,循環調用接口添加屬性值

    實現方法

    示例代碼

    // 原始數據
    let list = [{ id: 1 }, { id: 2 }, { id: 3 }]
    // 期望得到的數據[{ id: 1 }, { id: 2, asyncData: 'asyncData2' }, { id: 3, asyncData: 'asyncData3' }]
    // 模擬接口調用
    async function job(id) {
    	return `asyncData${id}`
    }

    forEach 遍歷

    這可能是很多前端最先想到的方法

    function asycTraversal() {
    	list.forEach(async item => {
    		if (item.id != 1) {
    			item.asyncData = await job(item.id)
    		}
    	})
    	console.log(list)
    }

    執行結果是

    { id: 1 }, { id: 2 }, { id: 3 }]

    因為 forEach 根本不支持異步寫法

    map 遍歷

    既然 forEach 不行,那我們再來試試 map 呢

    function asycTraversal() {
    	list.map(async item => {
    		if (item.id != 1) {
    			return {
    				...item,
    				asyncData: await job(item.id),
    			}
    		} else {
    			return item
    		}
    	})
    	console.log(list)
    }

    執行結果是

    { id: 1 }, { id: 2 }, { id: 3 }]

    結果是 map 遍歷也不行。我還試了 entries 遍歷,也是不行的。
    類似于 map 等傳入一個回調函數作為參數的循環方式都無法處理異步

    for 循環

    async function asycTraversal() {
    	console.time('111')
    	for (let i = 0; i < list.length; i++) {
    		job(list[i].id).then(res => {
    			list[i].id !== 1 && (list[i].asyncData = res)
    		})
    	}
    	console.log('list', list)
    	console.timeEnd('111')
    }

    執行結果是

    { id: 1 }, { id: 2 }, { id: 3 }]

    for 循環好像不行?我們再試試 await 關鍵字

    async function asycTraversal() {
    	console.time('111')
    	for (let i = 0; i < list.length; i++) {
    		list[i].id !== 1 && (list[i].asyncData = await job(list[i].id))
    	}
    	console.log('list', list)
    	console.timeEnd('111')
    }

    執行結果是

    list [
      { id: 1 },
      { id: 2, asyncData: 'asyncData2' },
      { id: 3, asyncData: 'asyncData3' }
    ]
    111:4.418ms

    這樣寫是得到了我們的的期望的結果,但很明顯循環中的異步是串行執行的,時間復雜度是 O(n)。
    我們希望他可以并行執行,并且還要保證所有的異步都執行完畢才執行下一步。并行執行我們留到最后說。

    for-of 循環

    async function asycTraversal() {
    	console.time('111')
    	for (const item of list) {
    		item.id !== 1 && (item.asyncData = await job(item.id))
    	}
    	console.log('list', list)
    	console.timeEnd('111')
    }

    執行結果是

    list [
      { id: 1 },
      { id: 2, asyncData: 'asyncData2' },
      { id: 3, asyncData: 'asyncData3' }
    ]
    111:4.286ms

    這種寫法與 for 循環一樣,異步也是串行執行的。

    我們再試試 then 的寫法

    async function asycTraversal() {
    	console.time('111')
    	for (const item of list) {
    		job(item.id).then(res => {
    			item.id !== 1 && (item.asyncData = res)
    		})
    	}
    	console.log('list', list)
    	console.timeEnd('111')
    }

    執行結果是

    { id: 1 }, { id: 2 }, { id: 3 }]

    與 for 循環一樣,使用 then 方法也是不行的。雖然 await 是可以的,但是這有一個弊端,就是不能像在 then 方法里面做一些其他的操作。

    for-await-of

    async function asycTraversal() {
    	console.time('111')
    	for await (const item of list) {
    		item.id !== 1 && (item.asyncData = await job(item.id))
    	}
    	console.log('list', list)
    	console.timeEnd('111')
    }

    執行結果是

    list [
      { id: 1 },
      { id: 2, asyncData: 'asyncData2' },
      { id: 3, asyncData: 'asyncData3' }
    ]
    111:4.452ms

    這種寫法異步也是串行執行的。

    我們再試試 then 的寫法

    async function asycTraversal() {
    	console.time('111')
    	for await (const item of list) {
    		job(item.id).then(res => {
    			item.id !== 1 && (item.asyncData = res)
    		})
    	}
    	console.log('list', list)
    	console.timeEnd('111')
    }

    哇哦,也是可以的,這樣我們就解決了 for-of 中的弊端。但不影響它的異步還是串行執行的。

    Promise.all

    最后終于可以來到并行執行的環節了

    async function asycTraversal() {
    	console.time('111')
    	const listPromises = list.map(item => {
    		return new Promise(async resolve => {
    			if (item.id == 1) {
    				resolve(item)
    			} else {
    				resolve({
    					...item,
    					asyncData: await job(item.id),
    				})
    			}
    		})
    	})
    	await Promise.all(listPromises).then(res => {
    		list = res
    	})
    	console.log('list', list)
    	console.timeEnd('111')
    }

    執行結果是

    list [
      { id: 1 },
      { id: 2, asyncData: 'asyncData2' },
      { id: 3, asyncData: 'asyncData3' }
    ]
    111:5.073ms

    好尷尬,執行時間變長了 T_T。大家可能跟我有一樣的疑惑不是并行執行的嗎,執行時長更短才對呀!!!
    沒關系,其實是因為異步寫得很簡單,實際應用中,比如發起網絡請求,請求的時長就會很長,就可以看出并行執行的優勢了。
    這里我還是模擬一下異步函數執行時間比較長的情況吧

    // 這里我們更新一下job函數
    function job(id) {
    	return new Promise(resolve => {
    		setTimeout(() => {
    			resolve(`asyncData${id}`)
    		}, id * 2000)
    	})
    }

    Promise.all 的執行結果

    list [
      { id: 1 },
      { id: 2, asyncData: 'asyncData2' },
      { id: 3, asyncData: 'asyncData3' }
    ]
    111: 6.010s

    而其他串行執行的方法,執行時長為

    111: 10.016s

    可以看出還是差了近一半。

    TODO 但是這里有個問題 T_T,更新后的 job 函數,for-await-of 用 then 的寫法失靈了,得不到我們期望了結果了,也是無解,期望大家來幫忙解答一下

    附加內容

    既然 forEach 不支持異步遍歷,那我們自己來實現一個可以異步遍歷的 forEach 吧

    // 并行實現
    async function _forEach(arr, fn) {
    	const fns = []
    	for (let i = 0; i < arr.length; i++) {
    		const item = arr[i]
    		fns.push(fn(item, i, arr))
    	}
    	await Promise.all(fns)
    }
    // 串行實現
    async function _forEach(arr, fn) {
    	for (let i = 0; i < arr.length; i++) {
    		const item = arr[i]
    		await fn(item, i, arr)
    	}
    }
    // 使用
    async function asycTraversal() {
    	await _forEach(list, async item => {
    		item.id !== 1 && (item.asyncData = await job(item.id))
    	})
    	console.log('list', list)
    }
    asycTraversal()

    執行結果都是

    list[({ id: 1 }, { id: 2, asyncData: 'asyncData2' }, { id: 3, asyncData: 'asyncData3' })]

    以上就是“JS異步遍歷如何實現”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    js
    AI

    友谊县| 伊吾县| 西藏| 阿拉尔市| 永善县| 新野县| 天津市| 绵竹市| 漳平市| 定州市| 湖口县| 安多县| 土默特左旗| 甘泉县| 房产| 张家港市| 全椒县| 靖江市| 河东区| 桃江县| 叶城县| 姚安县| 郧西县| 离岛区| 修文县| 浦江县| 镇雄县| 顺平县| 蓬莱市| 林口县| 白山市| 青田县| 乌什县| 龙南县| 金秀| 黄石市| 翁牛特旗| 屯昌县| 蒙城县| 太白县| 曲周县|