­

【面試Vue全家桶】vue前端交互模式-es7的​語法結構?async/await

  • 2020 年 2 月 13 日
  • 筆記

作者 | Jeskson

掘金 | https://juejin.im/user/5a16e1f3f265da43128096cb

2020.1.12

前端發請求,調用後端接口,來獲取特定格式的數據,老闆問了,你會前後端交互模式嗎?vue的那種。異步接口調用,常常使用到的語法,promise的概念是什麼呢?調用接口的方式,第一種為,fetch進行接口調用,第二種為,axios進行接口的調用。

es7的語法結構?async/await方式調用接口,基於不同接口的調用方式來實現案例。

讓我們了解一下前後端的交互模式,學習一下promise的語法,來回答面試官的問題,基於promise來實現異步調用,就算你會promise?那你了解fetch用法和async/await用法嗎?處理異步調用接口的方式。

網上一圖,回調地獄:看到暈,使代碼難以理解和維護。

前後端的交互是什麼

前後端的交互就是前端的瀏覽器去調用後端的接口,拿到後端的數據,在做前端的處理,進行渲染。客戶端與服務器的通信模式,前後端交互,調用接口的方法,第一種,原生的ajax,第二種,基於jquery的ajax,第三種,基於fetch,第四種,基於axios。

前端是通過請求地址向後端發送請求的,標準的url格式是什麼樣的呢?

格式如下:

schema://host:port/path?query#fragment

第一個schema為協議,比如http,https,ftp等,第二個,host為域名或者ip地址,第三個port為端口,http默認為80端口,是可以省略的,第四個path為路徑,比如/index,第五個query為查詢參數,比如name=dada&age=12,第六個fragment為錨點,哈希Hash,是用於定位頁面的某個位置。

符合規則的url有哪些是正確的呢?

http://www.dada.cnhttp://www.dada.cn/index/dadahttp://www.dada.cn/index/dada?name=dadahttp://www.dada.cn/index/dada?name=dada#theme

新型的url地址,restful形式的。HTTP的請求方式,第一種,使用GET為查詢,第二種,使用POST為添加,第三種,使用PUT為修改,第四種,使用DELETE為刪除。

符合規則的url地址:

http://www.dada.com/index GEThttp://www.dada.com/index POSThttp://www.dada.com/index/1 PUThttp://www.dada.com/index/2 DELETE

promise對象

promise用於表示一個異步操作的最終完成(或失敗),以及結果值。

Promise對象有以下兩個特點

對象的狀態不受外界影響

一旦狀態改變,就不會再變,任何時候都可以得到這個結果

constpromise1 =newPromise(function(resolve, reject){ setTimeout(function(){ resolve('foo'); },300);});promise1.then(function(value){console.log(value);// expected output: "foo"});console.log(promise1);// expected output: [object Promise]

語法:

newPromise(function(resolve, reject){…}/* executor */);

因為 Promise.prototype.then 和 Promise.prototype.catch 方法返回promise 對象, 所以它們可以被鏈式調用。

promise用法

promise是什麼呢?它是用於異步計算,將異步操作隊列化,按照期望的順序執行,返回符合預期的結果,可以在對象之間傳遞和操作promise。

創建promise

constda =newPromise((resolve, reject) =>{// resolve(someValue); // fulfilled// reject("failure reason"); // rejected});

functionda(url){returnnewPromise((resolve, reject) =>{constxhr =newXMLHttpRequest(); xhr.open("GET", url); xhr.onload =()=>resolve(xhr.responseText); xhr.onerror =()=>reject(xhr.statusText); xhr.send(); });};

簡單的實例

newPromise(resolve=>{ setTimeout(()=>{ resolve('hello') },2000)}).then(res=>{console.log(res)})

異步操作,事件監聽

document.getElementById('#start').addEventListener('click',start,false);functionstart(){// 響應事件,進行相應的操作}//jquery on 監聽$("#start").on("click", start)

回調

$.ajax(url, { success(res) { }})// 在頁面加載完畢後回調$(function(){// 頁面結構加載完成})

在JavaScript中,異步情況,第一種為定時任務,第二種為ajax,第三種事件函數。

newPromise(function(resolve, reject){ resolve('成功')// 數據處理完成// reject('失敗') // 數據處理出錯}).then((res) =>{console.log(res)},// 成功(err) => {console.log(err)}// 失敗)

異步編程與promise

$.ajax({

url: '',

success: function(data) {

console.log(data)

}

});

index.js

constexpress =require('express')constapp = express()constbodyParser =require('body-parser')// 處理靜態資源app.use(express.static('public'))// 處理參數app.use(bodyParser.json());app.use(bodyParser.urlencoded({extended:false}));// 設置允許跨域訪問服務app.all("*",function(req,res,next){ res.header("Access-Control-Allow-Origin","*"); res.header("Access-Control-Allow-Methods","PUT,GET,POST,DELETE,OPTIONS"); res.header("Access-Control-Allow-Headers","X-Requested-With"); res.header("Access-Control-Allow-Headers","Content-Type"); next();});// 路由app.get('/data', (req,res) => { res.send("hello world!")})// 啟動監聽app.listen(3000, () => {console.log("runing…")})

異步編程,多次異步調用,結果順序結果不確定

promise是異步編程的一種解決方案,從語法上來講,promise是一個對象,從它可以獲取異步操作的消息。使用promise的好處有哪些呢?

它可以避免多層異步調用嵌套問題(回調地獄),promis對象提供了簡潔的api,使得控制異步操作更加容易。回調地獄,多層嵌套請求問題,請求接口調用後台數據,有兩種可能性,一種為成功回調,一種為失敗回調,成功後寫一下成功後的操作代碼,失敗後也要寫一下失敗後的操作代碼。

在JavaScript中的世界裏,所有的代碼都是單線程執行的。因為這個缺點,所以會導致在JavaScript中的所有網絡操作,瀏覽器事件,都必須是異步執行的,異步執行可以用回到函數實現。

functioncallback(){console.log("dada");}console.log("dada setTimeout()");setTimeout(callback,1000);// 1秒後調用callback函數

注意,異步操作會在將來某個時間點觸發一個函數調用。

ajax的經典異步操作

request.onreadystatechange = function() {

if(request.readyState === 4) {

if(request.status === 200) {

return success(request.responseText);

}else{

return fail(request.status);

}

}

}

'usestrict';

new Promise(function() {} );

// 直接運行測試:

console.log('支持Promise!');

如果同時發送多個ajax的請求,返回來的結果是不確定的,要想返回的結果順序確定下來,就必須進行嵌套,如果嵌套就會有回調地獄的問題,這樣導致的代碼可讀性就會降低,所以就有promise語法來解決這一回調地獄的問題。

所以promise的出現的好處就是為了解決地獄回調,可以避免嵌套問題,和簡潔的代碼結構,可讀性增強。

console.log(typeofPromise)

示例

letda =newPromise(function(resolve, reject){// 當異步代碼執行成功時,會調用 resolve(…)// 當異步代碼失敗時, 會調用 reject(…)//使用setTimeout(…)來模擬異步代碼setTimeout(function(){ resolve("成功!"); },250);});da.then(function(res){//res的值是上面調用resolve(…)方法傳入的值.console.log("dada"+ res);});

promise的基本用法

首先實例化promise對象,構造函數中傳遞函數,該函數中用於處理異步任務,有兩個參數,resolve和reject用於處理成功和失敗的兩種情況,並通過p.then獲取處理結果。

then()方法返回一個promise:

constda =newPromise(function(resolve, reject){ resolve('da!');});da.then(function(value){console.log(value);// expected output: "da!"});

語法

p.then(onFulfilled[, onRejected]);

p.then(value => {

// fulfillment

}, reason => {

// rejection

});

var dada = new Promise((resolve, reject) => {

resolve('成功!');

// or

// reject(new Error("出錯了!"));

});

dada.then(value => {

console.log(value); // 成功!

}, reason => {

console.error(reason); // 出錯了!

});

catch()方法返回一個promise,並且處理拒絕的情況

p.catch(onRejected);p.catch(function(reason){// 拒絕});

finally()方法返回一個promise,在promise結束時,無論結果是fulfilled或者是rejected,都會執行指定的回調函數。

p.finally(onFinally);p.finally(function(){// 返回狀態為(resolved 或 rejected)});

newPromise(resolve=>{ setTimeout(()=>{ resolve('hello') },2000) }).then(val=>{console.log(val)// 參數val = 'hello'returnnewPromise(resolve=>{ setTimeout(()=>{ resolve('world') },2000) }) }).then(val=>{console.log(val)// 參數val = 'world'})

代碼例子:

varp =newPromise(function(resolve, reject){// 成功回調 resolve()// 失敗回調 reject()});p.then(function(ret){// resolve得到正常的結果},function(ret){// reject得到錯誤的結果});

resolve作用為將promise對象的狀態從「未完成」變成為「成功」,即是從Pending變為resolved,在異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去,而reject的作用是將promise對象的狀態從「未完成」變成「失敗」,就是從Pending變成rejected,在異步操作失敗時調用,並將異步操作報出的錯誤,作為參數傳遞出去。

promise有三種狀態,第一種為Pending,待定,初始狀態,第二種狀態為fulfilled,實現,操作成功,第三種狀態為rejected,被否決,操作失敗。

當promise狀態發生改變時,就會觸發then()裏面的響應函數處理,promise狀態一旦改變,就不會再變了。所以promis對象的狀態改變有兩種情況,第一種,從pending變為fulfilled,第二種為,從pending變為rejected。

基於promise處理ajax請求,處理原生ajax

functionqueryData(url){returnnewPromise(function(resolve,reject){varxhr =newXMLHttpRequest(); xhr.onreadystatechange =function(){if(xhr.readyState !=4)return;if(xhr.status ==200) { resolve(xhr.responseText) }else{ reject('出錯了'); } } xhr.open('get',url); xhr.send(null); })}

發送多個ajax請求

queryData()

.then(function(data){

return queryData();

})

.then(function(data){

return queryData();

})

.then(function(data){

return queryData();

});

// return 是新的promise對象

then參數中的函數返回值

第一種,返回promsie實例對象,返回的實例對象會調用下一個then

第二種,返回普通值,返回的普通值會直接傳遞給下一個then,通過then參數中函數的參數接收該值

promise常用的api

實例方法有三種,第一種,p.then()得到異步任務的正確結果,第二種,p.catch()獲取異常信息,第三種,p.finally()成功與否都會執行。

queryData() .then(function(data){console.log(data); }) .catch(function(data){console.log(data); }) .finally(function(){console.log('finished');});

promise常用api-實例方法

functionda(){returnnewPromise(function(resolve, reject){ setTimeout(function(){// resolve(123);reject('error'); },100);})}da() .then(function(data){console.log(data) }) .catch(function(data){console.log(data) }) .finally(function(){console.log('dada') });

da().then(function(data){console.log(data)},function(data){console.log(data)}).finally(function(){console.log('dada')});

對象方法

promise.all()並發處理多個異步任務,所有任務都執行完成才能得到結果

promise.race()並發處理多個異步任務,只要有一個任務完成就能得到結果

Promise.all([p1,p2,p3]).then(result) => {console.log(result);})Promise.race([p1,p2,p3]).then(result) => {console.log(result);})

代碼:

functionqueryData(url){returnnewPromise(function(resolve, reject){varxhr =newXMLHttpRequest(); xhr.onreadystatechange =function(){if(xhr.readyState !=4)return;if(xhr.readyState ==4&& xhr.status ==200) {// 處理正常的情況resolve(xhr.responseText); }else{// 處理異常情況reject('服務器出錯'); }; xhr.open('get',url); xhr.send(null); }); }varp1 = queryData(url);varp2 = queryDate(url1);Promise.all([p1,p2]).then(function(result){console.log(result)})

在promise中常用到回調函數延時綁定,返回值,錯誤冒泡。

constpromise =newPromise((resolve, reject) =>{console.log(1) resolve()console.log(2)})promise.then(()=>{console.log(3)})console.log(4)VM49:21VM49:42VM49:94VM49:73undefined

其中,promise構造函數是執行同步的作用,promise.then是執行異步函數的操作。

letpro =newPromise(resolve=>{ setTimeout(()=>{ resolve('hello world') },2000) }) setTimeout(()=>{ pro.then(value=>{console.log(value)// hello world}) },2000)

接口調用fetch的用法

fetch的概述,它更加簡單的數據獲取方式,功能更加強大,更加靈活,基於promise實現的。

語法結構:

fetch(url).then().then()….catch()

fetch的基本用法

fetch('/da').then(data=>{returndata.text();}).then(ret={console.log(ret);});

text()方法屬於fetchapi中的一部分,它返回一個promise實例對象,用於獲取後台返回的數據。

fetch請求參數

method(string)

http請求方法,默認為GET,可以使用POST,PUT,DELETE

body(string)

http的請求參數

headers(object)

http的請求頭

fetch('/da', { method;'get'}).then(data=>{returndata.text();}).then(ret=>{console.log(ret);});

GET請求方式的參數傳遞

fetch('/da?id=123').then(data=>{returndata.text();}).then(ret=>{console.log(ret);});fetch('/da/123', {method:'get'}).then(data=>{returndata.text();}).then(ret=>{console.log(ret);});

delete請求方式的參數傳遞

fetch('/da/123', {method:'delete'}).then(data=>{returndata.text();}).then(ret=>{console.log(ret);});

fetch請求參數的post請求方式的參數傳遞

fetch('/da', {method:'post',body:'name=dada',headers: {'content-Type':'application/x-www-form-urlencoded', } }).then(data=>{returndata.text(); }).then(ret=>{console.log(ret); });

post請求方式的參數傳遞

fetch('/da', {method:'post',body:JSON.stringify({name:'dada',age:12}) headers;{'Conent-Type':'application/json', } }).then(data=>{returndata.text(); }).then(ret=>{console.log(ret);});

fetch響應結果

響應數據格式

text()

將返回體處理成字符串類型

json()

返回結果和json.parse(presponseText)相同

接口調用axios用法

第三方的庫,很強大,是一個局域promise用於瀏覽器和node.js的HTTP客戶端。

它的特性,第一點是支持瀏覽器和node.js,第二點是支持promise,第三點,能夠攔截請求和響應,第四點,可以自動轉換json類型。

axios的基本用法

axios.get('/dada').then(ret=>{console.log(ret.data);});

axios的常用api

get,查詢數據,post,添加數據,put,修改數據,delete,刪除數據。

get傳遞參數,第一,通過url傳遞參數,第二種,通過params傳遞參數

axios.get('/da?id=123').then(ret=>{console.log(ret.data);})

restful傳參

axios.get('/dada/123')

.then(ret=>{

console.log(ret.data)

})

axios.get('/da', {params: { id:123}}).then(ret=>{console.log(ret.data)})

delete傳遞參數

參數傳遞方式與get類似

axios.delete('/da?id=1)

.then(ret=>{

console.log(ret.data)

})

axios.delete('/da/2)

.then(ret=>{

console.log(ret.data)

})

axios.delete('/da', {

params: {

id:1

}

})

.then(ret=>{

console.log(ret.data);

})

post傳遞參數

axios.post('/da', { name;'dada',}).then(res=>{console.log(res.data)})

默認傳遞的是json格式的數據。

post傳遞參數,通過URLSearchParams傳遞參數

application/x-www-form-urlencoded

constparams =newURLSearchParams();params.append('param1','value1');params.append('param2','value2');axios.post('/api/da', params).then(res=>{console.log(res.data)})

put傳遞參數

參數傳遞方式與post類似

axios.put('/da/1', {name:'dada',}).then(res=>{console.log(res.data)})

axios的響應結果

data為響應回來的數據,headers為響應頭信息,status為響應狀態碼,statusText響應狀態信息。

axios.post('/da-json').then(res=>{

console.log(res)

})

axios的全局 配置

axios.default.timeout = 3000; // 超時時間

axios.default.baseURL = 'http…' // 默認地址

axios.default.headers['mytoken'] = 'xxxx' //設置請求頭

// 配置請求的基準url地址axios.default.baseURL ='http://localhost:xxx/';axios.get('da-json').then(function(res){console.log(res.data.name);});

axios攔截器

axios.interceptors.request.use(function(config){//在拿過去發出之前進行一些信息設置returnconfig;},function(err){// 處理響應的錯誤信息});

在獲取數據之前對數據做一些加工處理。

接口調用async/await用法

async/await是es7引入的語法,更加方便了異步操作。

asyncfunctionqueryData(id){constres =awaitaxios.get('/data');returnres;}queryData.then(res=>{console.log(res)})

async關鍵字用於函數上,await關鍵字用於async函數中。

asyncfunctionname([param[, param[, … param]]]){ statements }name: 函數名稱param: 要傳遞給函數的參數的名稱statements: 函數體語句返回值: 返回的Promise對象會以asyncfunction的返回值進行解析或者以該函數拋出的異常進行回絕。

多個異步請求的async/await處理

asyncfunctionqueryData(id){constda1 =awaitaxios.get('/da1');constda2 =awaitaxios.get('/da2?name=dada');returnres;}queryData.then(res=>{console.log(res)})

出現了async/await之前,我們有三種異步書寫我們的代碼,第一,嵌套回調,第二,以promise為主的鏈式回調,使用generators。

async function dada(x) {

let a = 1;

return x+a;

}

undefined

dada(10);

Promise {<resolved>: 11}__proto__:

Promisecatch: ƒ catch()constructor:

ƒ Promise()finally: ƒ finally()then:

ƒ then()Symbol(Symbol.toStringTag):

"Promise"__proto__: Object[[PromiseStatus]]:

"resolved"[[PromiseValue]]:

11

await只能在async函數內部使用,用在普通函數里就會報錯。async/await實際上是Generator的語法糖。async關鍵字代表後面的函數中有異步操作,await表示等待一個異步方法執行完成。async 函數返回一個Promise對象,因此 async 函數通過 return 返回的值,會成為 then 方法中回調函數的參數。

await 就是異步等待,它等待的是一個Promise,async函數調用不會造成代碼的阻塞,但是await會引起async函數內部代碼的阻塞。

帶async關鍵字的函數,是聲明異步函數,返回值是promise對象

asyncfunctiontest(){return'da'}test();返回值為Promise{:"da"}。

宏任務和微任務都是隊列

宏任務有script、setTimeout、setInterval等

微任務有Promise.then,catch,finally,process.nextTick等

參考地址

https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544