您好,登錄后才能下訂單哦!
這篇文章主要介紹了JavaScript之怎么手寫asyncAdd方法的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇JavaScript之怎么手寫asyncAdd方法文章都會有所收獲,下面我們一起來看看吧。
在掘金上發現一道既簡單但個人覺得還挺有意思的一道題,題目如下:
// 異步加法 function asyncAdd(a,b,cb){ setTimeout(() => { cb(null, a + b) }, Math.random() * 1000) } async function total(){ const res1 = await sum(1,2,3,4,5,6,4) const res2 = await sum(1,2,3,4,5,6,4) return [res1, res2] } total() // 實現下 sum 函數。注意不能使用加法,在 sum 中借助 asyncAdd 完成加法。盡可能的優化這個方法的時間。 function sum(){ }
這里先放置最終結論:
只能修改 sum
部分的內容,sum
可接收任意長度的參數
sum
中只能通過 asyncAdd
實現加法計算
sum
中需要處理異步邏輯,需要使用 Promise
需要優化 sum
方法的計算時間
下面是分別通過對代碼的不同部分進行分析,獲取到的相關的信息。
// 實現下 sum 函數。注意不能使用加法,在 sum 中借助 asyncAdd 完成加法。盡可能的優化這個方法的時間。 function sum(){ }
最直觀的方式就是通過上述的文字描述部分,可以很容易知道題目具體要求:
實現 sum
函數,即只能修改 sum
部分的內容
不能直接使用加法(+),通過 asyncAdd
實現加法
優化 sum
方法的計算時間
// 異步加法 function asyncAdd(a, b, cb){ setTimeout(() => { cb(null, a + b) }, Math.random() * 1000) }
從上述內容來看,最明顯的就是 setTimeout
和 cb
了,其實這不難理解因為在 asyncAdd
中使用了 setTimeout
只能通過回調函數 cb
將本次計算結果返回出去,那其中的第一個參數 null
代表什么呢?
其實可以認為它是一個錯誤信息對象,如果你比較了解 node
的話,就會知道在 node
中的異步處理的回調函數通常第一個參數就是錯誤對象,用于傳遞給外部在發生錯誤時自定義后續執行邏輯等。
一句話: cb
函數會接收 錯誤對象 和 計算結果 作為參數傳遞給外部。
async function total(){ const res1 = await sum(1,2,3,4,5,6,4) const res2 = await sum(1,2,3,4,5,6,4) return [res1, res2] }
從上述的這部分來看,sum
方法的 返回值 肯定是一個 promise
類型的,因為最前面明顯的使用了 await sum(...)
的形式。
另外 total
函數返回值也必然是一個 promise
類型,因為整個 total
函數被定義為了一個 async
異步函數,可點擊此處查看詳細內容。
一句話:sum
需要返回 promise
類型的值,即 sum
一定會使用到 promise
,并且從 sum(1,2,3,4,5,6,4)
可知 sum
可接收任意長度的參數。
實現思路如下:
考慮到外部參數長度不固定,使用剩余運算符接收所有傳入的參數
考慮到 asyncAdd
中的異步操作,將其封裝為 Promise
的實現,即 caculate
函數
考慮到 asyncAdd
實際只能一次接收兩個數字進行計算,使用循環的形式將多個參數分別傳入
考慮到通過循環處理異步操作的順序問題,使用 async/await
來保證正確的執行順序,且 async
函數的返回值正好符合 sum
是 Promise
類型的要求
具體代碼如下:
// 通過 ES6 的剩余運算符(...) 接收外部傳入長度不固定的參數 async function sum(...nums: number[]) { // 封裝 Promise function caculate(num1: number, num2: number) { return new Promise((resolve, reject) => { // 調用 asyncAdd 實現加法 asyncAdd(num1, num2, (err: any, rs: number) => { // 處理錯誤邏輯 if (err) { reject(err); return; } // 向外部傳遞對應的計算結果 resolve(rs); }); }) } let res: any = 0; // 通過遍歷將參數一個個進行計算 for (const n of nums) { // 為了避免異步執行順序問題,使用 await 等待執行結果 res = await caculate(res, n); } return res; }
caculate
函數可抽離到 sum
函數外層
asyncAdd
函數的回調函數沒必要抽離,因為它依賴的參數和外部方法太多
function caculate(num1: number, num2: number) { return new Promise((resolve, reject) => { asyncAdd(num1, num2, (err: any, rs: number) => { if (err) { reject(err); return; } resolve(rs); }); }) } async function sum(...nums: number[]) { let res: any = 0; for (const n of nums) { res = await caculate(res, n); } return res; }
其實你仔細觀察 total
方法,其中 sum
調用了兩次,而且參數還是一模一樣的,目的就是提示你在第二次計算相同內容時結果直接 從緩存中獲取,而不是在通過異步計算。
async function total(){ const res1 = await sum(1,2,3,4,5,6,4) const res2 = await sum(1,2,3,4,5,6,4) return [res1, res2] }
以下只是一個簡單的緩存方案的實現,不必過于糾結,具體實現如下:
const cash: any = {}; function isUndefined(target: any) { return target === void 0; } async function sum(...nums: number[]) { let res: any = 0; const key = nums.join('+'); if (!isUndefined(cash[key])) return cash[key]; for (const n of nums) { res = await caculate(res, n); } cash[key] = res; return res; } function caculate(num1: number, num2: number) { return new Promise((resolve, reject) => { asyncAdd(num1, num2, (err: any, rs: number) => { if (err) { reject(err); return; } resolve(rs); }); }) }
關于“JavaScript之怎么手寫asyncAdd方法”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“JavaScript之怎么手寫asyncAdd方法”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。