JS 是但執行緒,一次只能執行一個任務,任務執行完後才能執行下一個,它會「阻塞」其他任務,這個任務可稱為主執行緒
JS中常見的非同步呼叫
① 定時任務
② Ajax
③事件函數
非同步模式可以一起執行多個任務,但是結果順序不確定,結果依賴於請求的這個程式的順序
如許要規定結果列印的順序就需要函數巢狀,但是函數巢狀會形成回撥地獄,於是就需要用到 promise
Promise
是非同步程式設計的一種解決方案,Promise
是一個函數,函數也是物件,可以當作建構函式 new
出來
使用:
new
範例化 Promise
物件resolve
和 reject
處理成功和失敗,這兩個引數都是方法可以直接呼叫p.then
處理結果 let p = new Promise(function (resolve, reject) {
setTimeout(function () {
let flag = false
if (flag) {
resolve(1);
} else {
reject(2);
}
}, 100)
})
p.then(function (data) {
console.log(data);
}, function (info) {
console.log(info);
})
1.返回promise範例物件
返回的該範例物件會呼叫下一個 then
2.返回普通值
如果 .then
返回的是一個普通值,那麼這個 then
會自動產生一個預設的 promise
物件,保證下一個 then
的使用,可以繼續進行鏈式操作
<script type="text/javascript">
/*
基於Promise傳送Ajax請求
*/
function queryData(url) {
# 1.1 建立一個Promise範例
var p = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState != 4) return;
if(xhr.readyState == 4 && xhr.status == 200) {
# 1.2 處理正常的情況
resolve(xhr.responseText);
}else{
# 1.3 處理異常情況
reject('伺服器錯誤');
}
};
xhr.open('get', url);
xhr.send(null);
});
return p;
}
# 注意: 這裡需要開啟一個服務
# 在then方法中,你也可以直接return資料而不是Promise物件,在後面的then中就可以接收到資料了
queryData('http://localhost:3000/data')
.then(function(data){
console.log(data)
# 1.4 想要繼續鏈式程式設計下去 需要 return
return queryData('http://localhost:3000/data1');
})
.then(function(data){
console.log(data);
return queryData('http://localhost:3000/data2');
})
.then(function(data){
console.log(data)
});
</script>
實體方法
.then()
得到非同步任務正確的結果
.catch()
獲取異常資訊
.finally()
成功與否都會執行(不是正式標準)
靜態方法(物件方法)
.all()
Promise.all
方法接受一個陣列作引數,陣列中的物件(p1、p2、p3)均為promise範例(如果不是一個promise,該項會被用Promise.resolve
轉換為一個promise)。它的狀態由這三個promise範例決定
.race()
Promise.race
方法同樣接受一個陣列作引數。當p1, p2, p3中有一個範例的狀態發生改變(變為fulfilled
或rejected
),p的狀態就跟著改變。並把第一個改變狀態的promise的返回值,傳給p的回撥函數
var p1 = queryData('http://localhost:3000/a1');
var p2 = queryData('http://localhost:3000/a2');
var p3 = queryData('http://localhost:3000/a3');
Promise.all([p1,p2,p3]).then(function(result){
// all 中的引數 [p1,p2,p3] 和 返回的結果一 一對應["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
console.log(result) //["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
})
Promise.race([p1,p2,p3]).then(function(result){
// 由於p1執行較快,Promise的then()將獲得結果'P1'。p2,p3仍在繼續執行,但執行結果將被丟棄。
console.log(result) // "HELLO TOM"
})
// 先用 then 的方式得到 text 的資料
fetch('/wwwww').then(data=>{
// text 是 fetch 的一部分 返回值是一個 promise 範例物件 用於獲取後臺返回的資料
return data.text()
// 然後通過下一個 then 得到具體的資料
}).then(ret=>{
console.log(ret);
})
fetch API 中的 HTTP 請求
//Fetch API 呼叫介面傳遞引數
//1.1 GET引數傳遞 - 傳統URL 通過url ? 的形式傳參
fetch('http://localhost:3000/books?id=123', {
// get 請求可以省略不寫 預設的是GET
method: 'get'
})
.then(function (data) {
// 它返回一個Promise範例物件,用於獲取後臺返回的資料
return data.text();
}).then(function (data) {
// 在這個then裡面我們能拿到最終的資料
console.log(data)
});
//1.2 GET引數傳遞 restful形式的URL 通過/ 的形式傳遞引數 即 id = 456 和id後臺的設定有關
fetch('http://localhost:3000/books/456', {
// get 請求可以省略不寫 預設的是GET
method: 'get'
})
.then(function (data) {
return data.text();
}).then(function (data) {
console.log(data)
});
//2.1 DELETE請求方式引數傳遞 刪除id 是 id=789
fetch('http://localhost:3000/books/789', {
method: 'delete'
})
.then(function (data) {
return data.text();
}).then(function (data) {
console.log(data)
});
//3 POST請求傳參
fetch('http://localhost:3000/books', {
method: 'post',
// 3.1 傳遞資料
body: 'uname=lisi&pwd=123',
// 3.2 設定請求頭
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(function (data) {
return data.text();
}).then(function (data) {
console.log(data)
});
// POST請求傳參
fetch('http://localhost:3000/books', {
method: 'post',
body: JSON.stringify({
uname: '張三',
pwd: '456'
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(function (data) {
return data.text();
}).then(function (data) {
console.log(data)
});
// PUT請求傳參 修改id 是 123 的
fetch('http://localhost:3000/books/123', {
method: 'put',
body: JSON.stringify({
uname: '張三',
pwd: '789'
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(function (data) {
return data.text();
}).then(function (data) {
console.log(data)
});
fetchAPI 中 響應格式
text()
將返回體處理成字串型別json()
返回結果和 JSON.parse(responseText)
一樣JSON
,BLOB
或者TEXT
等等//Fetch響應結果的資料格式
fetch('http://localhost:3000/json').then(function (data) {
// return data.json();
// 將獲取到的資料使用 json 轉換物件
return data.text();
}).then(function (data) {
// console.log(data.uname)
// console.log(typeof data)
var obj = JSON.parse(data);
console.log(obj.uname, obj.age, obj.gender)
})
axios.get('/www')
.then(ret=>{
// data 的名字是固定的,它用於獲取後臺響應的資料
console.log(ret.data);
})
查詢資料 get
刪除資料 delete
新增資料 post
修改資料 put
//# 1. 傳送get 請求
axios.get('http://localhost:3000/adata').then(function (ret) {
//#拿到 ret 是一個物件 所有的物件都存在 ret 的data 屬性裡面
// 注意data屬性是固定的用法,用於獲取後臺的實際資料
// console.log(ret.data)
console.log(ret)
})
//# 2. get 請求傳遞引數# 2.1 通過傳統的url 以 ? 的形式傳遞引數
axios.get('http://localhost:3000/axios?id=123').then(function (ret) {
console.log(ret.data)
})
//# 2.2 restful 形式傳遞引數
axios.get('http://localhost:3000/axios/123').then(function (ret) {
console.log(ret.data)
})
//# 2.3 通過params 形式傳遞引數
axios.get('http://localhost:3000/axios', {
params: {
id: 789
}
}).then(function (ret) {
console.log(ret.data)
})
//#3 axios delete 請求傳參 傳參的形式和 get 請求一樣
axios.delete('http://localhost:3000/axios', {
params: {
id: 111
}
}).then(function (ret) {
console.log(ret.data)
})
//# 4 axios 的 post 請求# 4.1 通過選項傳遞引數
axios.post('http://localhost:3000/axios', {
uname: 'lisi',
pwd: 123
}).then(function (ret) {
console.log(ret.data)
})
//# 4.2 通過 URLSearchParams 傳遞引數
var params = new URLSearchParams();
params.append('uname', 'zhangsan');
params.append('pwd', '111');
axios.post('http://localhost:3000/axios', params).then(function (ret) {
console.log(ret.data)
})
//#5 axios put 請求傳參 和 post 請求一樣
axios.put('http://localhost:3000/axios/123', {
uname: 'lisi',
pwd: 123
}).then(function (ret) {
console.log(ret.data)
})
// 設定公共的預設地址
axios.defaults.baseURL = 'https://api.example.com';
// 設定 超時時間
axios.defaults.timeout = 2500;
// 設定公共的請求頭
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// 設定公共的 post 的 Content-Type
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
請求攔截器
響應攔截器
//# 1. 請求攔截器
axios.interceptors.request.use(function (config) {
console.log(config.url)
//# 1.1 任何請求都會經過這一步 在傳送請求之前做些什麼
config.headers.mytoken = 'nihao';
//# 1.2 這裡一定要return 否則設定不成功
return config;
}, function (err) {
//#1.3 對請求錯誤做點什麼
console.log(err)
})
//#2. 響應攔截器
axios.interceptors.response.use(function (res) {
//#2.1 在接收響應做些什麼
var data = res.data;
return data;
}, function (err) {
//#2.2 對響應錯誤做點什麼
console.log(err)
})
async作為一個關鍵字放到函數前面
async
函數都會隱式返回一個promise
await
關鍵字只能在使用 async
定義的函數中使用
async/await 讓非同步程式碼看起來、表現起來更像同步程式碼
//# 1. async 基礎用法
//# 1.1 async作為一個關鍵字放到函數前面
async function queryData() {
//# 1.2 await關鍵字只能在使用async定義的函數中使用 await後面可以直接跟一個 Promise範例物件
var ret = await new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('nihao')
}, 1000);
})
// console.log(ret.data)
return ret;
}
//# 1.3 任何一個async函數都會隱式返回一個promise 我們可以使用then 進行鏈式程式設計
queryData().then(function (data) {
console.log(data)
})
//#2. async 函數處理多個非同步函數
axios.defaults.baseURL = 'http://localhost:3000';
async function queryData() {
//# 2.1 新增await之後 當前的await 返回結果之後才會執行後面的程式碼
var info = await axios.get('async1');
//#2.2 讓非同步程式碼看起來、表現起來更像同步程式碼
var ret = await axios.get('async2?info=' + info.data);
return ret.data;
}
queryData().then(function (data) {
console.log(data)
})