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