摘要:最近在寫一個程序,功能是下載頁面上的資源,首先拿到頁面資源鏈接列表,如要求是資源并行下載,所有資源下載結束后通知,收集錯誤的下載鏈接。如果把上面模擬請求的注釋去掉,還會發現是在結束后就執行了,而后面的請求還未結束。
最近在寫一個Node.js程序,功能是下載頁面上的資源,首先拿到頁面資源鏈接列表,如:
[ "https://xxx.com/img/logo.jpg", "https://xxx.com/img/bg.jpg", "https://xxx.com/css/main.css", "https://xxx.com/css/animate.css", "https://xxx.com/js/jquery.js", "https://xxx.com/js/form.js", ... ]
要求是資源并行下載,所有資源下載結束后通知,收集錯誤的下載鏈接。
如果是傳統做法是遍歷數組發送請求,聲明一個變量記錄請求數,不管成功或失敗,結束后都給這個變量+1,并且調用一個函數,這個函數判斷當前變量是否等于數組長度,相等則表示所有請求已經完成。
// pseudo code var count = 0 var errs = [] var data = [...] function request(url) { ajax({url: url}) .success(function () { count++ callback() }) .fail(function () { count++ errs.push(...) callback() }) } function callback() { if (count === data.length) { console.log("done!") } } data.forEach(request)
因為請求是異步的,我們也無法確定每個請求花費的時間,所以只能在回調里處理。現在我們有了Promise,async-await,支持同步的寫法,那可以怎么寫呢?
我們用setTimeout來模擬請求,數據data = [500, 400, 300, 200, 100]既是每個請求返回的數據也是每個請求所需的時間。
如果是繼發請求(一個請求結束后再請求后一個),那么應該是按順序打印,理論上所有請求的總時間等于每個請求所花時間之和,約等于1500ms;如果是并發請求(假設請求數不會太多,不超過限制),順序是按時間從小到大打印,理論上所有請求的總時間等于最長的那個時間,約等于500ms。
首先先看下怎么并行請求和請求結束確定
// 模擬請求 function request(param) { return new Promise(resolve => { setTimeout(() => { console.log(param) resolve() }, param) }) } const items = [500, 400, 300, 200, 100]
? 直接for循環
(() => { for (let item of items) { request(item) } console.log("end") })() // 輸出:end, 100, 200, 300, 400, 500
上面的輸出可以看出,請求是并行的,但是無法確定什么結束
? for循環,使用async-await
(async () => { for (let item of items) { await request(item) } console.log("end") })() // 輸出:500, 400, 300, 200, 100, end
上面的代碼可以看出,雖然確定了結束,但請求是繼發的
? 使用Promise.all
(() => { Promise.all(items.map(request)).then(res => { console.log("end") }) })() // 輸出:100, 200, 300, 400, 500, end
上面的代碼可以看出,請求是并發的,并且在所有請求結束后打印end,滿足條件
我們不能保證所有的請求都是正常的,接下來看看當有請求出錯時怎么處理,假設200的請求出錯
function request(param) { return new Promise((resolve, reject) => { setTimeout(() => { if (param === 200) { // console.log(param, " failed") return reject({ status: "error", data: param }) } // console.log(param, " success") resolve({ status: "success", data: param }) }, param) }) } const items = [500, 400, 300, 200, 100]
Promise有catch方法捕獲錯誤,最近新增的finally方法能在最后執行
(() => { Promise.all(items.map(request)) .then(res => { console.log(res) }) .catch (err => { console.log(err) }) .finally(res => { console.log("end", res) }) })() // 輸出 {status: "error", data: 200}, end, undefined
上面的輸出可以看出,如果有錯誤,則不會進入then,而是進入catch,然后進入finally,但是finally不接受參數,只告訴你結束了。如果把上面模擬請求的console.log(...)注釋去掉,還會發現finally是在catch結束后就執行了,而200后面的請求還未結束。
接下來我們改造下模擬請求,在請求出錯后就catch錯誤
function request(param) { return new Promise((resolve, reject) => { setTimeout(() => { if (param === 200) { // console.log(param, " failed") return reject({ status: "error", data: param }) } // console.log(param, " success") resolve({ status: "success", data: param }) }, param) }).catch(err => err) } (() => { Promise.all(items.map(request)) .then(res => { console.log(res, "end") }) })() // 輸出 [{…}, {…}, {…}, {stauts: "error", data: 200}, {…}], end
這樣就可以在then中拿到全部的結果了,如果要用for循環的話也是可以的
(async () => { const temp = [] // 這個for循環的作用和上面的map類似 for (let item of items) { temp.push(request(item)) } const result = [] for (let t of temp) { result.push(await t) } console.log(result, "end") })() // 輸出與上面一致
第一個for循環保證并發請求,保存了Promise,第二個循環加入await保證按順序執行。
好了,以上就是全部內容,你有更好的寫法嗎?
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106106.html
摘要:而且只要他更新完畢對修飾的變量賦值,那么讀線程立馬可以看到最新修改后的數組,這是保證的。這個時候,就采用了思想來實現這個,避免更新的時候阻塞住高頻的讀操作,實現無鎖的效果,優化線程并發的性能。 今天聊一個非常硬核的技術知識,給大家分析一下CopyOnWrite思想是什么,以及在Java并發包中的具體體現,包括在Kafka內核源碼中是如何運用這個思想來優化并發性能的。這個CopyOnW...
摘要:具體來說,就是在寫數據庫的時候同時寫一份數據到緩存集群里,然后用緩存集群來承載大部分的讀請求。各種精妙的架構設計因此一篇小文頂多具有拋磚引玉的效果但是數據庫優化的思想差不多就這些了 前言 數據庫優化一方面是找出系統的瓶頸,提高MySQL數據庫的整體性能,而另一方面需要合理的結構設計和參數調整,以提高用戶的相應速度,同時還要盡可能的節約系統資源,以便讓系統提供更大的負荷. 1. 優化一覽...
摘要:以下為大家整理了阿里巴巴史上最全的面試題,涉及大量面試知識點和相關試題。的內存結構,和比例。多線程多線程的幾種實現方式,什么是線程安全。點擊這里有一套答案版的多線程試題。線上系統突然變得異常緩慢,你如何查找問題。 以下為大家整理了阿里巴巴史上最全的 Java 面試題,涉及大量 Java 面試知識點和相關試題。 JAVA基礎 JAVA中的幾種基本數據類型是什么,各自占用多少字節。 S...
閱讀 3448·2023-04-26 00:39
閱讀 4039·2021-09-22 10:02
閱讀 2532·2021-08-09 13:46
閱讀 1098·2019-08-29 18:40
閱讀 1444·2019-08-29 18:33
閱讀 773·2019-08-29 17:14
閱讀 1513·2019-08-29 12:40
閱讀 2970·2019-08-28 18:07