promise 的由來
有時候我們做ajax請求,可能會遇到以下這種情況
requsetA > requsetB > requestC
requestB的請求依賴requestA的數據,requestC的請求依賴requestB的數據。在沒有異步編程的概念那時,我們往往只能通過回調函數的方法去解決這個問題。
requestA(function(res){
requestB(function(res){
requestC(function(res){
//do something
})
})
})
其實也不是很難看,比較有層次感,哈哈。。。
然而,實際情況并不會想現在那樣那么簡單,你可能還需要將requestA的數據進行一些處理才能夠傳給requestB,requestB請求回來的數據,又得做一些處理才能傳給requestC,那么這就會變成一團巨大的函數體,可讀性十分糟糕。
所以就有了promise對象的出現,它是專治多重依賴的異步操作的。
我們可以使用promise來改寫以上代碼
promise走起
//定義 一個promise對象,進行requestA異步請求
let pro = new Promise((resolve,reject)=>{
requestA({//一些配置})
//jquery 1.8+ 新寫法,success已經過時
.done((data)=>{
//resolve方法將參數傳遞給下一個回調函數
resolve(data)
})
.error((err)=>{
reject(err);
})
})
//進行requestB異步請求
let requestB = (res)=>{
let pro1 = new Promise((resolve,reject)=>{
reqb({//一些配置})
.done((data)=>{
console.log(res);
resolve(data);
})
.error((err)=>{
reject(err);
})
})
//進行requestC異步請求
let requestC = (res)=>{
let pro2 = new Promise((resolve,reject)=>{
reqc({//一些配置})
.done((data)=>{
console.log(res);
console.log(data);
})
.error((err)=>{
reject(err);
})
})
//然后 ,使用優雅的方式進行異步回調
pro.then(requestB)
.then(requestC)
promise與傳統的ajxa同步請求
讓我們先來做一個實驗
- 寫段簡單的服務端代碼,以php為例
<?php
//睡眠5秒,模擬真實網絡請求環境
sleep(5);
//防止跨域請求
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:POST,GET');
//獲取前端get請求參數,返回
$usript = $_GET['keyword'];
echo $usript;
?>
- 封裝原生ajax請求
//使用 ES6賦值解構語法
function ajax({url,test,bool,callback}){
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function() {
if (ajax.readyState == 4 && ajax.status == 200) {
var response = ajax.responseText;
Object.prototype.toString.call(callback) === '[object Function]' && callback(response)
test && console.timeEnd(test)
}
};
ajax.open("GET", url, bool);
ajax.setRequestHeader("Content-type", "text/plain");
ajax.send();
}
- 編寫同步測試代碼
//使用chrome控制臺api 的console.time()進行計時操作
ajax({
url:"http://192.168.1.105/index.php?keyword=123",
bool:false,
callback:(res)=>{
ajax({
url:"http://192.168.1.105/index.php?keyword=123",
test:'sync test',
bool:false,
callback:(data) => console.log(`${res} -requestA: ${data}`)
})
}
})
console.log('hello promise')
結果
123
test.html:15 sync test: 10014.349ms
hello promise
結果顯而易見ajax同步請求會阻塞javascript運行,導致其后的代碼阻塞等待,嚴重拖低性能
- 編寫異步測試代碼
console.time('async test')
let pro = new Promise((resolve,reject)=>{
ajax({
url:"http://192.168.1.105/index.php?keyword=123",
bool:true,
callback:(data)=>{
if(data){
resolve(data);
}else{
reject('請求錯誤!')
}
}
})
})
let requestA = (res)=>{
let resA = new Promise((resolve,reject)=>{
ajax({
url:"http://192.168.1.105/index.php?keyword=123",
bool:true,
callback:(data)=>{
if(data){
console.log(`${res} -requestA: ${data}`)
}else{
reject('請求錯誤!')
}
},
test:'async test'
})
})
}
pro.then(requestA);
console.log('hello promise')
結果
hello promise
test.html:62 123 -requestA: 123
test.html:15 async test: 10022.117ms
promise是異步的,引擎執行代碼的時候會先將異步代碼掛起,先去執行其他代碼,等待上一個請求結束再回過頭來執行下一個請求的代碼,所以,雖然promise和ajax同步請求用的時間一樣多,也可以說promise就是在做同步請求,但是promise本身是異步的,并不會阻塞代碼,所以你可以看到先打印出了hello promise