es6基礎 --- 9、異步編程 promise

異步編程

js中的單線程是指負責執行代碼的線程只有一個,這樣設計的初衷是js是用來操作DOM的,多線程會產生DOM操作衝突。

缺點:執行耗時任務時會阻塞代碼執行,出現假死狀態。

解決:有同步模式和異步模式。JS代碼執行是單線程,但是瀏覽器是多線程的,因此可以借用瀏覽器的多線程去執行一些耗時任務,如ajax請求。是同步模式還是異步模式是由運行環境提供的API來決定的。

取個例子:一段代碼中用promise封裝了一個ajax請求,利用瀏覽器的多線程去請求這個ajax請求,該段代碼繼續執行,請求完成後,promise.then中的回調函數會添加到代碼段的最後去執行。這樣,解決了耗時任務阻塞代碼執行的問題。

回調函數

回調函數就是將你想要做的事情寫在一個函數中,並把這個函數作爲另一個函數的參數交給執行者去執行。舉個例子:

                // 回調函數作爲參數交給執行者,讓執行者決定想什麼情況下執行
		function foo(callback) {
			setTimeout(function() {
				callback()
			}, 1000)
		}
		// 回調函數
		function callback() {
			console.log('這是我想要做的事情')
		}
		foo(callback)

Promise

promise初始化

Promise是一個構造函數,promise對象初始化如下:

                // 參數是一個函數,函數裏面是你需要執行的函數,並根據結果調用相應的函數,
		// resolve將狀態改爲resolved,並將結果傳給then中的第一個回調函數參數
		// resolve將狀態改爲rejected,並將結果傳給then中的第二個回調函數參數
		const p = new Promise(function(resolve, reject) {
			resolve('success')
		})
		// 不同結果的相應回調函數,成功了執行第一個函數,失敗了執行第二個函數
		p.then(res => {
			console.log(res)
		}, err => {
			console.log(err)
		})

用Promise封裝Ajax請求:

                function ajax (url) {
			return new Promise((resolve, reject) => {
				const xhr = new XMLHttpRequest()
				xhr.onload = function () {
					if(this.status === 200){
						resolve(this.response)
					}else{
						reject(new Error(this.statusText))
					}
				}
				xhr.responseType = 'json'
				xhr.open('GET', url)
				xhr.send()
			})
		}
		ajax('https://www.ctwing.cn/sysCategory/getCatTreeByCode/homepage_nav').then(res => {
			console.log('success', res)
		}, err => {
			console.log('fail', err)
		})

鏈式調用

如果一個請求的發起需要在另一個請求成功的基礎上,那麼如果寫在前一個then回調函數中,同樣會造成地獄回調的問題。promise提供了鏈式調用來解決這個問題。

promise.then返回的是一個全新的promise對象(不是像以往的那種return this來實現的)。鏈式調用時,每一個then方法都在爲上一個then返回的promise對象添加回調。

promise.then中也可以手動return一個promise對象作爲下一個then方法的promise對象。

異常處理

在鏈式調用中,如果異常捕獲寫在.then的第二個參數中,則只能捕獲當前promise的異常。如果寫在鏈條的最末端,那麼可以捕獲到鏈條上的所有異常,鏈條上任何一個異常都會被傳遞,直至被捕獲。

靜態方法

Promise.resolve() 快速創建一個狀態爲resolved的promise對象

  • 參數是一個原始值,或者是一個不具有then方法的對象,則Promise.resolve方法返回一個新的 Promise 對象
  • 參數是一個 Promise 實例,那麼Promise.resolve將不做任何修改、原封不動地返回這個實例。
  • 參數是一個有then方法的對象,將這個對象轉爲 Promise 對象,然後就立即執行thenable對象的then方法
  • 參數爲空,直接返回一個resolved狀態的 Promise 對象,resolvedValue爲undefined

Promise.reject() 快速創建一個狀態爲reject的promise對象

                const p = new Promise((resolve, reject) => {
			resolve('a promise Object')
		})
		const p1 = Promise.resolve('foo')
		 // Promise {<resolved>: "foo"}
			// __proto__: Promise
			// [[PromiseStatus]]: "resolved"
			// [[PromiseValue]]: "foo"
		const p2 = Promise.resolve(p)
		console.log(p2 === p)
		// true 
		const p3 = Promise.resolve({
			name: 'tom',
			then: function (resolve, reject) {
				console.log('name is: ' + this.name)
				resolve(this.name)
			}
		})
		// name is: tom 立即執行then方法
		// Promise {<resolved>: "tom"}
			// __proto__: Promise
			// [[PromiseStatus]]: "resolved"
			// [[PromiseValue]]: "tom"
		const p4 = Promise.resolve()
		// Promise {<resolved>: undefined}
		// 	__proto__: Promise
		// 	[[PromiseStatus]]: "resolved"
		// 	[[PromiseValue]]: undefined

Promise.all() 參數爲promise對象數組。返回一個新的promise對象,等待所有結果成功,新對象才返回成功,並將所有的結果傳遞給新對象,如果其中一個失敗,則新對象失敗,並返回第一個失敗的結果

Promise.race() 返回第一個完成的任務的結果

                const pro1 = new Promise((resolve, reject) => {
			setTimeout(function () {
				resolve('success1')
			}, 1000)
		})
		const pro2 = new Promise((resolve, reject) => {
			setTimeout(function () {
				resolve('success2')
			}, 3000)
		})
		const pro3 = new Promise((resolve, reject) => {
			setTimeout(function () {
				reject('failed1')
			}, 2000)
		})
		const proAll = Promise.all([pro1, pro2])
		// Promise {<resolved>: Array(2)}
			// 	__proto__: Promise
			// 	[[PromiseStatus]]: "resolved"
			// 	[[PromiseValue]]: Array(2)
			// 	0: "success1"
			// 	1: "success2"
			// 	length: 2
			// 	__proto__: Array(0)
		const proRace = Promise.race([pro1, pro2, pro3])
		// Promise {<resolved>: "success1"}
		// 	__proto__: Promise
		// 	[[PromiseStatus]]: "resolved"
		// 	[[PromiseValue]]: "success1"

小練習:帶有timeout的請求結果

                function request () {
			return new Promise((resolve, reject) => {
				setTimeout(function () {
					resolve('success')
				}, 2000)
			})
		}
		function timeout () {
			return new Promise((resolve, reject) => {
				setTimeout(function () {
					reject('time out!')
				}, 500)
			})
		}

		const newRequst = Promise.race([request(), timeout()])
		newRequst.then(res => {
			console.log(res)
		}).catch(err => {
			console.log(err)
		})

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章