① 第一步:callback
1. 方法回調
<template> <div class="hello"> <button type="button" @click="setCallBack()"> testCallback </button> </div> </template> <script> export default { name: 'callback', data () { return { result: 0 } }, methods: { setCallBack() { this.init((res) => { console.log(res) }) }, init(callback) { setTimeout(() => { if(Math.random() <= 0.6) { callback(1) } else { callback(2) } }, 100) } } } </script>
2:回調地獄
<template> <div class="hello"> <button type="button" @click="startCallback()"> test </button> </div> </template> <script> export default { name: 'callback', data () { return { result: 0 } }, methods: { startCallback(){ setTimeout(()=>{ console.log('callback 0.5秒',new Date()); setTimeout(()=>{ console.log('callback 0.4秒',new Date()); setTimeout(()=>{ console.log('callback 0.3秒',new Date()); setTimeout(()=>{ console.log('callback 0.2秒',new Date()); setTimeout(()=>{ console.log('callback 0.1秒',new Date()); }, 100); }, 200); }, 300); }, 400); }, 500); } } } </script>
3. 回調地獄的改善
<template> <div class="hello"> <button type="button" @click="startCallback()"> test </button> </div> </template> <script> export default { name: 'callback', data () { return { result: 0 } }, methods: { call1(next){ setTimeout(()=>{ console.log('callback 0.5秒',new Date()); next(); },500); }, call2(next){ setTimeout(()=>{ console.log('callback 0.4秒',new Date()); next(); },400); }, call3(next){ setTimeout(()=>{ console.log('callback 0.3秒',new Date()); next(); },300); }, call4(next){ setTimeout(()=>{ console.log('callback 0.2秒',new Date()); next(); },200); }, call5(){ setTimeout(()=>{ console.log('callback 0.1秒',new Date()); },100); }, startCallback(){ this.call1(()=>{ this.call2(()=>{ this.call3(()=>{ this.call4(()=>{ this.call5(); }); }); }); }); } } } </script>
② 第二步 : Promise
Promise他將提供一種更加優雅的方法,讓我們寫回調函數。
Promise是一個構造函數,自己身上有all、reject、resolve這幾個眼熟的方法,原型上有then、catch等同樣很眼熟的方法。
這么說用Promise new出來的對象肯定就有then、catch方法
Promise,簡單說就是一個容器,里面保存着某個未來才會結束的事件(通常是一個異步操作)的結果。
Promise 提供統一的 API,各種異步操作都可以用同樣的方法進行處理。
Promise對象有以下兩個特點:
(1)對象的狀態不受外界影響。Promise對象代表一個異步操作,有三種狀態:Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和Rejected(已失敗)。
只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從Pending變為Resolved和從Pending變為Rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果。就算改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
有了Promise對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的接口,使得控制異步操作更加容易。
簡單來說,Promise 就是用同步的方式寫異步的代碼,用來解決回調問題
<template> <div class="hello"> <button type="button" @click="startCallback()"> test </button> </div> </template> <script> export default { name: 'callback', data () { return { result: 0 } }, methods: { call1(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('callback 0.5秒',new Date()); resolve(); },500); }); return p; }, call2(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('callback 0.4秒',new Date()); resolve(); },400); }); return p; }, call3(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('callback 0.3秒',new Date()); resolve(); },300); }); return p; }, call4(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('callback 0.2秒',new Date()); resolve(); },200); }); return p; }, call5(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('callback 0.1秒',new Date()); resolve(); },100); }); return p; }, startCallback() { var self = this this.call1() .then(function(data){ return self.call2(); }) .then(function(data){ return self.call3(); }) .then(function(data){ return self.call4(); }) .then(function(data){ return self.call5(); }) } } } </script>
第三步: Async/await/Promise
Async/await的主要益處是可以避免回調地獄(callback hell且以最接近同步代碼的方式編寫異步代碼。
1.【方法中等待異步】
簡單理解:async 是讓方法變成異步 await是等待異步方法執行完畢。
<template>
<div class="hello">
<button type="button" @click="setPromise()"> test </button>
</div>
</template>
<script>
export default { name: 'HelloWorld', data () { return { result: 0 } }, methods: { setPromise() { var sleep = function (time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('ok'); // reject('error'); }, time); }) }; var start = async function (self) { try { console.log('start async'); self.result = await sleep(3000); // 這里得到了一個返回錯誤 console.log('async后:'+ self.result); // 收到 ‘ok’ } catch (err) { console.log(err); // 這里捕捉到錯誤 `error` } }; start(this) console.log('async ago '+ this.result); // 收到 ‘ok’ } } } </script>
2. 【復數異步方法】
復數異步方法順序執行
<template>
<div class="hello">
<button type="button" @click="setPromise()"> test </button>
</div>
</template>
<script>
export default { name: 'HelloWorld', data () { return { result: 0 } }, methods: { setPromise() { let initIndex = function(self) { Promise.resolve().then(function(){ console.log('step 1: start') return self.init() }).then(function(res) { console.log('step 2: ' + res) return self.getToken() }).then(function(token) { console.log('step 3: ' + token) return self.getServerData(1) }).then(function(data) { console.log('step 4: ' + data) return self.getServerData(2) }).then(function(data) { console.log('step 5: ' + data) console.log('finish') }) } initIndex(this) }, init() { return new Promise((resolve, reject) => { resolve('return true') }) }, getToken() { return new Promise((resolve, reject) => { resolve('return token') }) }, getServerData(data) { return new Promise((resolve, reject) => { resolve('return getServerData' + data) }) } } } </script>
3. 【復數異步方法】
復數方法優先執行
<template>
<div class="hello">
<button type="button" @click="setPromise()"> test </button>
</div>
</template>
<script>
export default { name: 'HelloWorld', data () { return { result: 0 } }, methods: { setPromise() { let $init = this.init() let $getToken = this.getToken() let $getServerData1 = this.getServerData(1) let $getServerData2 = this.getServerData(2) Promise.all([$init, $getToken, $getServerData1, $getServerData2]).then((values) => { console.log(values) console.log('finish') }); }, init() { return new Promise((resolve, reject) => { resolve('return true') }) }, getToken() { return new Promise((resolve, reject) => { resolve('return token') }) }, getServerData(data) { return new Promise((resolve, reject) => { resolve('return getServerData' + data) }) } } } </script>
4.【循環中等待異步】
<template>
<div class="hello">
<button type="button" @click="setAgvList()"> test </button>
<ul v-for="item in items">
<li>{{item.count}}:{{item.name}}</li>
</ul>
</div>
</template>
<script>
export default { name: 'HelloWorld', data () { return { items: [] } }, methods :{ setAgvList() { const commonAsync = async() => { for (var count = 0; count < 5; count++) { var name = await this.getRobotByIndex(count) var status = { count: count, name: name } this.items.push(status) } console.log(this.items) } commonAsync() }, async getRobotByIndex (agvIndex) { return "hello world!" + agvIndex } } } </script>