① 第一步: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>
