JS 異步編程與Promise async await語法糖

promise

這裏新構建了一個函數readSync包裝了一下,讓它返回一個Promise.

//json數據
{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "sourceMap": true
  },
  "exclude": [
    "node_modules"
  ]
}

function readData(){
        return new Promise((resolve,reject)=>{
            $.ajax({
				url:'./tsconfig.json',
				success:(res)=>{
				   resolve(res)  //用resolve返回成功的res數據
				},
				error:(res)=>{
				    reject(res)  //用reject返回失敗的數據
				}
			})
		})
	}
	readData()
        .then(data => console.log(JSON.parse(data).compilerOptions.module))  //commonjs
        .catch(reason => console.error(reason));

async/await語法糖

async-await是promise和generator的語法糖

簡單來說:async-await 是建立在 promise機制之上的,並不能取代其地位。

最後藉助es7給出的async/await語法糖,將讓異步等待,變成同步.

function readData(){
        return new Promise((resolve,reject)=>{
            $.ajax({
				url:'./tsconfig.json',
				success:(res)=>{
				   resolve(res)  //用resolve返回成功的res數據
				},
				error:(res)=>{
				    reject(res)  //用reject返回失敗的數據
				}
			})
		})
}

async function readData2(){
        let res = await readData();
        console.log(JSON.parse(res).compilerOptions.module)
}
readData2()   //commonjs

這裏,有新增加了一個函數:readData2,藉助async/await語法糖,這樣就變成同步代碼了.

.then()方法中的數據變成了返回值.

不過Prmoise中他的prototype中有一個all方法:

Promise.all(iter)

如果你在一個函數中有多個await,這個樣子線程阻塞,很耗費時間,Promise.all方法,可以將多個await變成並行的去await.

async就相當於promise 而await就相當於 then
整個的內部是一樣的只是表現的形式不一樣了而已
需要注意的是async指定了函數 才能在那個函數裏面寫await

async  結合 promise使用

async function demo01() {
    return 123;
}

demo01().then(val => {
    console.log(val);// 123
});
若 async 定義的函數有返回值,return 123;相當於Promise.resolve(123),沒有聲明式的 return則相當於執行了Promise.resolve();

await

await 可以理解爲是 async wait 的簡寫。await 必須出現在 async 函數內部,不能單獨使用。

function notAsyncFunc() {
    await Math.random();
}
notAsyncFunc();//Uncaught SyntaxError: Unexpected identifier

await 後面可以跟任何的JS 表達式。雖然說 await 可以等很多類型的東西,但是它最主要的意圖是用來等待 Promise 對象的狀態被 resolved。如果await的是 promise對象會造成異步函數停止執行並且等待 promise 的解決,如果等的是正常的表達式則立即執行。

function sleep(second){
	       return new Promise((resolve,reject)=>{
               setTimeout(()=>{
                   resolve('enough sleep~~~')
			   },second)
		   })
	   }
	   function normalFun(){
	       console.log('normalFun')
	   }
	   async function awaitDemo(){
	       await normalFun();
           console.log('something, ~~');
	       let res = await sleep(2000)
		   console.log(res)
	   }
       awaitDemo()   //normalFun
	                 //something, ~~
	                 //enough sleep~~~

真實情況下的應用

情況一:reject 的處理

爲了處理Promise.reject 的情況我們應該將代碼塊用 try catch 包裹一下

function sleep(){
	      return new Promise((resolve,reject)=>{
              $.ajax({
                  url:'./tsconfig.json1',  //地址故意寫錯
                  success:(res)=>{
                      resolve(res)  //用resolve返回成功的res數據
                  },
                  error:(res)=>{
                      reject(res)  //用reject返回失敗的數據
                  }
              })
		  })
	  }
	  async function asyncDemo() {
		  try{
		      let result = await sleep()
			  console.log("success-----",result)
		  }catch(err){
              console.log("error---",err)
		  }
      }
      asyncDemo()   //error--- {readyState: 4, getResponseHeader: ƒ, ...}

有了 try catch 之後我們就能夠拿到 Promise.reject 回來的數據了。

情況二:有三個請求需要發生,第三個請求是依賴於第二個請求的解構第二個請求依賴於第一個請求的結果。

function sleep(second, param) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(param);
        }, second);
    })
}

async function test() {
    let result1 = await sleep(2000, 'req01');
    let result2 = await sleep(1000, 'req02' + result1);
    let result3 = await sleep(500, 'req03' + result2);
    console.log(`
        ${result3}
        ${result2}
        ${result1}
    `);
}

情況三:三個異步操作 相互沒有關聯 只是需要當請求都結束後將界面的 loading 清除掉即可

使用Promise.all()

 function sleep() {
		  return new Promise((resolve,reject)=>{
              $.ajax({
                  url:'./tsconfig.json',
                  success:(res)=>{
                      resolve(JSON.parse(res).compilerOptions.target)  //用resolve返回成功的res數據
                  },
                  error:(res)=>{
                      reject(res)  //用reject返回失敗的數據
                  }
              })
		  })
 }
    async function asyncDemo(){
        let p1 = sleep();
        let p2 = sleep();
        let p3 = sleep();
        let res = await Promise.all([p1,p2,p3]);
        console.log('clear the loading~')   //這樣是錯誤的
    }
    asyncDemo()

情況四:await in for 循環

最後一點了,await必須在async函數的上下文中的。

// 正常 for 循環
async function forDemo() {
    let arr = [1, 2, 3, 4, 5];
    for (let i = 0; i < arr.length; i ++) {
        await arr[i];
    }
}
forDemo();//正常輸出
// 因爲想要炫技把 for循環寫成下面這樣
async function forBugDemo() {
    let arr = [1, 2, 3, 4, 5];
    arr.forEach(item => {
        await item;
    });
}
forBugDemo();// Uncaught SyntaxError: Unexpected identifier

 

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