一道前端面試題引發的學習

追_光_者發表於2019-03-17

題目:

請實現如下函式,可以批量請求資料,所有的 url 地址在 urls 引數中,同時可以通過 max 引數控制請求的併發數,當所有請求結束之後,需要執行 callback 回撥函式,傳送請求的函式可以直接使用 fetch 即可

小白陷阱

題中有一個關鍵詞“併發”,對於我這種前端小白第一次解答這道題目就掉入陷阱了, 解成了並行,?

概念解析

說到併發我們可以先來理解‘序列’,‘並行’,‘併發’這三個概念
複製程式碼
  • 序列 當前任務執行完之後,才能執行下一個任務
  • 並行 多工同時進行,互不影響
  • 併發 多工在同一時間間隔發生

舉個例子來幫助我們更好的理解:比如一個人洗衣服跟燒菜

  • 序列就是: 你只能先做其中的某一件事,做完之後才能去做下一件事情
  • 並行就是: 你右手燒菜,左手洗衣服同時進行
  • 併發就是: 你一會兒燒菜,一會兒又去洗衣服

到這裡相信大家對上述的三個概念有了一點了解,接下里我們就來實現上面這道面試題:

試題實現

	<script type="text/javascript">
		let bodyElement = document.body
	    let urls = [
	      'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2580986389,1527418707&fm=27&gp=0.jpg',
	      'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1995874357,4132437942&fm=27&gp=0.jpg',
	      'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2640393967,721831803&fm=27&gp=0.jpg',
	      'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1548525155,1032715394&fm=27&gp=0.jpg',
	      'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2434600655,2612296260&fm=27&gp=0.jpg',
	      'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2160840192,133594931&fm=27&gp=0.jpg'
	    ]
	    let max = 2
	    let callback = () => {
	      console.log('所有請求完成了')
	    }

	    class Concurrent {
	    	constructor(urls, max, callback) {
	    		this.urls = urls
	    		this.max = max
	    		this.callback = callback
	    	  	this.currentIndex = 0
	    	}

	    	addQueue() {
	    		for(let i = 0, len = this.urls.length; i < len; i++) {
	    			if (this.currentIndex < this.max) {
    					this.request()
    					break
	    			}
    				
    				this.currentIndex++
	    		}
	    	}

	    	request() {
	    		let tiemout = Math.random() * 1000
	    		
	    		fetch(this.urls[this.currentIndex])
	    		.then(res => res.blob())
	    		.then(res => {
	    			let src = URL.createObjectURL(res)
	    			bodyElement.innerHTML += `<img src=${src} />`
	    		})
	    		.catch(fail => {
	    			
	    		})
	    		.finally(() => {
	    			if (++this.currentIndex < this.urls.length) {
	    			    // 用延時器是因為反應介面太快 以便於觀察
	    				return setTimeout(() => {
		    				this.request()
		    			}, tiemout)
		    		}

		    		this.callback()
	    		})
	    	}
	    }

	    function sendRequest(urls, max, callback) {
			let concurrent = new Concurrent(urls, max, callback)
			concurrent.addQueue()
	    }

	    sendRequest(urls, max, callback)
	</script>
複製程式碼

謝謝大家的閱讀,有錯誤之處,敬請指教。

相關文章