一。js的異步
首先js語言的執行環境是單線程的即當一個任務完成時才能進行下一個任務 ,以此類推後面的任務都需要排隊執行。 這樣就會造成需要花費大量的時間執行完所有的任務,而且當一個任務中的代碼出現錯誤或者死循環時那麼下面的任務會無法執行。 所以Javascript在的處理模式分類異步和同步。 參考(https://juejin.im/post/5b605b035188251a90189c61)(https://es6.ruanyifeng.com/#docs/promise#Promise-all)
二。同步模式
後一個任務等待前一個任務結束,然後再執行,程序的執行順序與任務的排列順序是一致的、同步的;
三。異步模式
"異步模式"則完全不同,每一個任務有一個或多個回調函數(callback),前一個任務結束後,不是執行後一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行,所以程序的執行順序與任務的排列順序是不一致的、異步的。
四。常用的異步編程模式
回調函數 即f1,f2兩個函數,f2要等待f1執行結果後執行,即 f1(f2)
事件驅動的方式 f1.on('done', f2); (JQ寫法,f1完成時,trigger("done")則執行f2)
發佈-訂閱 模式
Promise對象實現
五。Promise的含義(https://es6.ruanyifeng.com/#docs/promise#Promise-all)
六。 基本用法
Promise對象是一個構造函數,用來生成Promise實例,Promise構造函數接收一個函數作爲參數,與此同時該函數參數接收resolve和reject作爲參數。 resolve將Promise的未成功狀態轉化成功的狀態。將異步操作成果的結果傳遞過去。 reject將未失敗轉換爲失敗,將執行失敗的結果傳過去。當實例執行完成之後可調用then方法指定成功或失敗的回調函數並執行後續的代碼。
sun = ({a,b}) => {
return new Promise((resolve, reject) => {
/** 假設在這裏執行了一些操作後得到其中的一個結果 **/
a >= b ? resolve("條件成立") : reject("條件不成立")
})
};
let a = sun({a:10,b:5}).then(data => {
console.log(data)
},error => {
console.log(error)
});
// 條件成立
let b = sun({a:1,b:10}).then(data => {
console.log(data)
},error => {
console.log(error)
});
// 條件不成立
七 Promise的特點
對象不受外界影響,初始狀態爲pending(等待中),結果的狀態爲resolve和reject之一
狀態只能由pending變爲另外兩種的其中一種,且改變後不可逆也不可再度修改,
let promise = new Promise((resolve, reject) => {
reject('我失敗了')
resolve('我成功了')
});
promise.then(data => {
console.log(data)
},error => {
console.log(error)
})
// 我失敗了
let promise = new Promise((resolve, reject) => {
resolve('我成功了')
reject('我失敗了')
});
promise.then(data => {
console.log(data)
},error => {
console.log(error)
})
// 我成功了
八。第一個axios的請求示例
假設我們這裏有三個axios的請求。要求是要求時第三個請求要在第二個完成時觸發。第二個要在第一個完成時觸發。 這時傳統的做法可能是。 只做示例
function request () {
axios.get('/user?ID=12345')
.then(function (response) {
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
})
.catch(function (error) {
console.log(error);
});
})
.catch(function (error) {
console.log(error);
});
}
或者
function request(callack) {
axios.get('/user?ID=12345')
.then(function (response) {
callack(response);
})
.catch(function (error) {
console.log(error);
});
}
request(data => {
if (data){
request(data1 => {
if (data1){
request(data3 => {
//
})
}
})
}
})
不難發現如果此時需要十個這樣的請求呢 ? 二十個...... 甚至更多時顯然不太現實。 此時嘗試用Promise實現
methods:{
getData({url} = {}){
return new Promise((resolve, reject) => {
this.axios.get(url).then(res => {
if (res.data.status === 0){
resolve(JSON.parse(res.data.data))
}
}).catch(error => {
reject(error)
})
})
},
}
mounted: function () {
this.getData({url:api.jiaoxuehot + 1}).then(data => {
this.getData({url:api.newUpload + 1}).then(data => {
console.log(data)
},error => {
console.log(error)
})
console.log(data)
},error => {
console.log(error)
})
}
(20) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
(20) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
首先我們不難發現通過創建Promise對象可以成功的拿到了我們想要的數據。 但是貌似這個和我們初衷並不符。也沒法解決多個請求所帶來的不便。
九。Promise.all()
該方法用於將多個Promise實例重新包裝成一個新的Promise實例。 嘗試用該方法解決上面未解決的問題
methods:{
getData({url} = {}){
return new Promise((resolve, reject) => {
this.axios.get(url).then(res => {
if (res.data.status === 0){
resolve(JSON.parse(res.data.data))
}
}).catch(error => {
reject(error)
})
})
},
}
mounted: function () {
const a = this.getData({url:api.jiaoxuehot + 1});
const b = this.getData({url:api.wenhuahot + 1});
Promise.all(new Array(2).fill(a,b)).then(data => {
console.log(data)
},error => {
console.log(error)
})
}
[Array(20), Array(20)]
我們驚奇的發現這個新的Promise對象居然返回了兩個數組。 且我們展開數據結構發現這正是我們想要的數據。到此爲止我們上面的問題也就得到了解決
從上面的代碼我們可以看出Promise.all()接受一個數組作爲參數。並且a, b 都是Promise的實例。 如果其中一個不是就會調用Promise.resolve方法將參數轉爲實例。此外Promise.all()不僅僅只接受數組。 實際上可以具有Iterator接口的數據
Promise.all(最終的狀態分爲兩種情況
1。a,b的狀態都爲fulfilled時。最終的結果才爲fulfilled
2。a,b其中一個的狀態爲rejected時。 最終結果爲rejected
十。Promise.race()
上面代碼中,只要a,b之中有一個實例率先改變狀態,p
的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給p
的回調函數。
Promise.race()
方法的參數與Promise.all()
方法一樣,如果不是 Promise 實例,就會先調用下面講到的Promise.resolve()
方法,將參數轉爲 Promise 實例,再進一步處理。
methods:{
getData({url} = {}){
return new Promise((resolve, reject) => {
this.axios.get(url).then(res => {
if (res.data.status === 0){
resolve(JSON.parse(res.data.data))
}
}).catch(error => {
reject(error)
})
})
},
}
mounted: function () {
const a = this.getData({url:api.jiaoxuehot + 1});
const b = this.getData({url:api.wenhuahot + 1});
Promise.race(new Array(2).fill(a,b)).then(data => {
console.log(data)
},error => {
console.log(error)
})
}
(20) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
十一。Promise.prototype.then()
Promise 實例具有then
方法,也就是說,then
方法是定義在原型對象Promise.prototype
上的。它的作用是爲 Promise 實例添加狀態改變時的回調函數。前面說過,then
方法的第一個參數是resolved
狀態的回調函數,第二個參數(可選)是rejected
狀態的回調函數。
十二。Promise.prototype.catch()
Promise.prototype.catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的別名,用於指定發生錯誤時的回調函數。
new Promise((resolve, reject) => {
throw new Error("我拋出了錯誤")
}).catch(error => {
console.log(error)
})
Error: 我拋出了錯誤
at eval (home.vue?250d:285)
at new Promise (<anonymous>)
at new F (_export.js?90cd:36)
at a.mounted (home.vue?250d:284)
at Re (vue.min.js:6)
at $t (vue.min.js:6)
at Object.insert (vue.min.js:6)
at A (vue.min.js:6)
at a.__patch__ (vue.min.js:6)
at a.e._update (vue.min.js:6)