前端为什么有的接口明明是成功回调却执行了.catch失败回调_Web前端:ES6是干什么的?(下)...
大家好,我來了!本期為大家?guī)淼腤eb前端學(xué)習(xí)知識是”Web前端:ES6是干什么的?(下)“,喜歡Web前端的小伙伴,一起看看吧!
主要內(nèi)容
學(xué)習(xí)目標(biāo)
第一節(jié) Promise
1.1 promise是什么?
Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大
有了Promise對象,就可以將異步操作以同步操作的流程表達(dá)出來,避免了層層嵌套的回調(diào)函數(shù)
1.2 promsie產(chǎn)生的原因
在JavaScript的世界中,所有代碼都是單線程執(zhí)行的。
由于這個(gè)“缺陷”,導(dǎo)致JavaScript的所有網(wǎng)絡(luò)操作,瀏覽器事件,都必須是異步執(zhí)行。異步執(zhí)行可以用回調(diào)函數(shù)實(shí)現(xiàn):
function callback() {console.log('Done'); } console.log('before setTimeout()'); setTimeout(callback, 1000); // 1秒鐘后調(diào)用callback函數(shù) console.log('after setTimeout()');觀察上述代碼執(zhí)行,在Chrome的控制臺輸出可以看到:
before setTimeout() after setTimeout() (等待1秒后) Done可見,異步操作會(huì)在將來的某個(gè)時(shí)間點(diǎn)觸發(fā)一個(gè)函數(shù)調(diào)用。
異步回調(diào)的問題:
- 之前處理異步是通過純粹的回調(diào)函數(shù)的形式進(jìn)行處理
- 很容易進(jìn)入到回調(diào)地獄中,剝奪了函數(shù)return的能力
- 問題可以解決,但是難以讀懂,維護(hù)困難
- 稍有不慎就會(huì)踏入回調(diào)地獄 - 嵌套層次深,不好維護(hù)
回調(diào)地獄
一般情況我們一次性調(diào)用API就可以完成請求。
有些情況需要多次調(diào)用服務(wù)器API,就會(huì)形成一個(gè)鏈?zhǔn)秸{(diào)用,比如為了完成一個(gè)功能,我們需要調(diào)用API1、API2、API3,依次按照順序進(jìn)行調(diào)用,這個(gè)時(shí)候就會(huì)出現(xiàn)回調(diào)地獄的問題
1.3 promise詳解
1.3.1 語法
new Promise(function (resolve, reject) {// 一段耗時(shí)的異步操作resolve('成功') // 數(shù)據(jù)處理完成// reject('失敗') // 數(shù)據(jù)處理出錯(cuò)}).then((res) => {console.log(res)}, // 成功(err) => {console.log(err)} // 失敗)resolve作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α?#xff08;即從 pending 變?yōu)?resolved),在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;
reject作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 ?#xff08;即從 pending 變?yōu)?rejected),在異步操作失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤,作為參數(shù)傳遞出去。
【代碼演示】
請求網(wǎng)絡(luò)接口:
圖片懶加載
1.3.2 promise有三個(gè)狀態(tài):
1、pending[待定]初始狀態(tài)
2、fulfilled[實(shí)現(xiàn)]操作成功
3、rejected[被否決]操作失敗
當(dāng)promise狀態(tài)發(fā)生改變,就會(huì)觸發(fā)then()里的響應(yīng)函數(shù)處理后續(xù)步驟;
promise狀態(tài)一經(jīng)改變,不會(huì)再變。
Promise對象的狀態(tài)改變,只有兩種可能:
從pending變?yōu)閒ulfilled
從pending變?yōu)閞ejected。
這兩種情況只要發(fā)生,狀態(tài)就凝固了,不會(huì)再變了。
1.4 promise案例
回調(diào)包裝成Promise,他有兩個(gè)顯而易見的好處:
1、可讀性好
2、返回 的結(jié)果可以加入任何Promise隊(duì)列
實(shí)戰(zhàn)示例,回調(diào)地獄和promise對比:
1.4.1 傳統(tǒng)寫法
/***第一步:找到北京的id第二步:根據(jù)北京的id -> 找到北京公司的id第三步:根據(jù)北京公司的id -> 找到北京公司的詳情目的:模擬鏈?zhǔn)秸{(diào)用、回調(diào)地獄***/// 回調(diào)地獄// 請求第一個(gè)API: 地址在北京的公司的id$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/city',success (resCity) {let findCityId = resCity.filter(item => {if (item.id == 'c1') {return item}})[0].id$.ajax({// 請求第二個(gè)API: 根據(jù)上一個(gè)返回的在北京公司的id “findCityId”,找到北京公司的 第一家公司的idurl: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/position-list',success (resPosition) {let findPostionId = resPosition.filter(item => {if(item.cityId == findCityId) {return item}})[0].id// 請求第三個(gè)API: 根據(jù)上一個(gè)API的id(findPostionId)找到具體公司,然后返回公司詳情$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/company',success (resCom) {let comInfo = resCom.filter(item => {if (findPostionId == item.id) {return item}})[0]console.log(comInfo)}})}})}})1.4.2 Promise
onst cityList = new Promise((resolve, reject) => {$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/city',success (res) {resolve(res)}})})// 第二步:找到城市是北京的idcityList.then(res => {let findCityId = res.filter(item => {if (item.id == 'c1') {return item}})[0].idfindCompanyId().then(res => {// 第三步(2):根據(jù)北京的id -> 找到北京公司的idlet findPostionId = res.filter(item => {if(item.cityId == findCityId) {return item}})[0].id// 第四步(2):傳入公司的idcompanyInfo(findPostionId)})})// 第三步(1):根據(jù)北京的id -> 找到北京公司的idfunction findCompanyId () {let aaa = new Promise((resolve, reject) => {$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/position-list',success (res) {resolve(res)}})})return aaa}// 第四步:根據(jù)上一個(gè)API的id(findPostionId)找到具體公司,然后返回公司詳情function companyInfo (id) {let companyList = new Promise((resolve, reject) => {$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/company',success (res) {let comInfo = res.filter(item => {if (id == item.id) {return item}})[0]console.log(comInfo)}})})}本章作業(yè)
Promise是什么 如何使用
第二節(jié)Generator
Generator 函數(shù)是 ES6 提供的一種異步編程解決方案,語法行為與傳統(tǒng)函數(shù)完全不同
2.1 Generator語法
形式上,Generator 函數(shù)是一個(gè)普通函數(shù),但是有兩個(gè)特征。一是,function關(guān)鍵字與函數(shù)名之間有一個(gè)星號;二是,函數(shù)體內(nèi)部使用yield表達(dá)式,定義不同的內(nèi)部狀態(tài)(yield在英語里的意思就是“產(chǎn)出”)。
function* getData() {yield http();yield getLog(); }// Generator函數(shù)function* generator() {yield 'status one' // yield 表達(dá)式是暫停執(zhí)行的標(biāo)記 return 'hello world'}let iterator = generator() // 調(diào)用 Generator函數(shù),函數(shù)并沒有執(zhí)行,返回的是一個(gè)Iterator對象iterator.next() // {value: "status one", done: false},value 表示返回值, done 表示遍歷還沒有結(jié)束iterator.next() // {value: "hello world", done: true},value 表示返回值, done 表示遍歷結(jié)束yield 表達(dá)式
由于 Generator 函數(shù)返回的遍歷器對象,只有調(diào)用next方法才會(huì)遍歷下一個(gè)內(nèi)部狀態(tài),所以其實(shí)提供了一種可以暫停執(zhí)行的函數(shù)。yield表達(dá)式就是暫停標(biāo)志。
遍歷器對象的next方法的運(yùn)行邏輯如下。
(1)遇到y(tǒng)ield表達(dá)式,就暫停執(zhí)行后面的操作,并將緊跟在yield后面的那個(gè)表達(dá)式的值,作為返回的對象的value屬性值。
(2)下一次調(diào)用next方法時(shí),再繼續(xù)往下執(zhí)行,直到遇到下一個(gè)yield表達(dá)式。
(3)如果沒有再遇到新的yield表達(dá)式,就一直運(yùn)行到函數(shù)結(jié)束,直到return語句為止,并將return語句后面的表達(dá)式的值,作為返回的對象的value屬性值。
function* getData() {yield http();yield getLog(); } function getLog() {console.log("我是網(wǎng)絡(luò)請求"); } function http() {return $.ajax({type: "get",url: "http://iwenwiki.com/api/blueberrypai/getIndexChating.php",success: function (data) {console.log(data);}}) }var gd = getData(); gd.next(); gd.next();2.2 async
ES2017 標(biāo)準(zhǔn)引入了 async 函數(shù),使得異步操作變得更加方便。
async 函數(shù)是什么?一句話,它就是 Generator 函數(shù)的語法糖
function getLog(result,ms) {console.log(result);// 頁面渲染函數(shù)$("#root").append(`<img src='${ result.titleImg }' />`);return new Promise((resolve) => {setTimeout(resolve, ms);}); }function Hello() {console.log("我是最后執(zhí)行"); }function http() {return $.ajax({type: "get",url: "http://iwenwiki.com/api/blueberrypai/getIndexChating.php",success: function (data) {console.log("網(wǎng)絡(luò)請求執(zhí)行完成");}}) }async function getData() {var result = await http();await getLog(result,2000);Hello(); } getData();本章作業(yè)
Generator 函數(shù)
第三節(jié) 模塊的導(dǎo)入導(dǎo)出
在es5中,用module.exports和exports導(dǎo)出模塊,用require引入模塊。
es6新增export和export default導(dǎo)出模塊,import導(dǎo)入模塊。
3.1名字導(dǎo)出(name export)
名字導(dǎo)出可以在模塊中導(dǎo)出多個(gè)聲明。
export
export后必須跟語句, 何為語句, 如聲明, for, if 等都是語句, export 不能導(dǎo)出匿名函數(shù), 也不能導(dǎo)出某個(gè)已經(jīng)聲明的變量, 如:
export const bar = function() {}; // 合法 export bar; // 非法 export 1; // 非法 export function foo () {}; // 合法, 后跟的是聲明語句 export { foo }; // 合法, 后面跟的{}理解為語句, 就像if后面的{}一樣 export { foo as bar }; // 合法export { foo: foo }; // 非法, 后面的{}被解析成對象3.2 默認(rèn)導(dǎo)出(default export)
一個(gè)模塊只能有一個(gè)默認(rèn)導(dǎo)出,對于默認(rèn)導(dǎo)出,導(dǎo)入的名稱可以和導(dǎo)出的名稱不一致,這對于導(dǎo)出匿名函數(shù)或類非常有用。
3.2.1 export default
export default在整個(gè)模塊中只能出現(xiàn)一次, 后只能具體的值, 何為具體的值, 如1, 2, 3, 再比如一個(gè)函數(shù)聲明(非表達(dá)式), 或者是一個(gè)類聲明(與函數(shù)聲明一個(gè)意思), 或者匿名函數(shù), 只要是能用變量接受的都可以, 例子:
export default 1; // 合法 export default function foo() {}; // 合法, 因?yàn)閒unction foo() {} 能被變量接受, 如 var bar = function foo() {} export default const bar = 1; // 非法, 因?yàn)関ar a = const bar = 1 是不合法的 export default { foo }; // 合法, {} 被理解為一個(gè)對象 export default { foo: foo }; // 合法, 同上3.2.2 import
import語法為:
import { x, y } from './test.js';import * as some from './test.js'; // 命名空間導(dǎo)入 import './test.js';import { default as test } from './test.js';導(dǎo)入再導(dǎo)出
export { some } from './test.js';export * from './test.js';導(dǎo)入后跟需要導(dǎo)入的綁定和模塊說明符, 導(dǎo)入綁定的列表并非對象的解構(gòu), 二者并無關(guān)聯(lián), 導(dǎo)入的標(biāo)識符很像const聲明的變量, 不可更改, 也同時(shí)存在暫時(shí)性死區(qū), 如有理解錯(cuò)誤的地方還請不吝指教
第四節(jié)Class類
傳統(tǒng)的javascript中只有對象,沒有類的概念。它是基于原型的面向?qū)ο笳Z言。原型對象特點(diǎn)就是將自身的屬性共享給新對象。這樣的寫法相對于其它傳統(tǒng)面向?qū)ο笳Z言來講,很有一種獨(dú)樹一幟的感腳!非常容易讓人困惑!
如果要生成一個(gè)對象實(shí)例,需要先定義一個(gè)構(gòu)造函數(shù),然后通過new操作符來完成。構(gòu)造函數(shù)示例:
4.1 類的定義
ES6引入了Class(類)這個(gè)概念,通過class關(guān)鍵字可以定義類。該關(guān)鍵字的出現(xiàn)使得其在對象寫法上更加清晰,更像是一種面向?qū)ο蟮恼Z言。如果將之前的代碼改為ES6的寫法就會(huì)是這個(gè)樣子:
注意項(xiàng)
1.在類中聲明方法的時(shí)候,千萬不要給該方法加上function關(guān)鍵字
2.方法之間不要用逗號分隔,否則會(huì)報(bào)錯(cuò)
由下面代碼可以看出類實(shí)質(zhì)上就是一個(gè)函數(shù)。類自身指向的就是構(gòu)造函數(shù)。所以可以認(rèn)為ES6中的類其實(shí)就是構(gòu)造函數(shù)的另外一種寫法!
console.log(typeof Person);//function console.log(Person===Person.prototype.constructor);//true以下代碼說明構(gòu)造函數(shù)的prototype屬性,在ES6的類中依然存在著。
console.log(Person.prototype);//輸出的結(jié)果是一個(gè)對象
實(shí)際上類的所有方法都定義在類的prototype屬性上。代碼證明下:
當(dāng)然也可以通過prototype屬性對類添加方法。如下:
還可以通過Object.assign方法來為對象動(dòng)態(tài)增加方法
constructor方法是類的構(gòu)造函數(shù)的默認(rèn)方法,通過new命令生成對象實(shí)例時(shí),自動(dòng)調(diào)用該方法。
constructor方法如果沒有顯式定義,會(huì)隱式生成一個(gè)constructor方法。所以即使你沒有添加構(gòu)造函數(shù),構(gòu)造函數(shù)也是存在的。constructor方法默認(rèn)返回實(shí)例對象this,但是也可以指定constructor方法返回一個(gè)全新的對象,讓返回的實(shí)例對象不是該類的實(shí)例。
constructor中定義的屬性可以稱為實(shí)例屬性(即定義在this對象上),constructor外聲明的屬性都是定義在原型上的,可以稱為原型屬性(即定義在class上)。hasOwnProperty()函數(shù)用于判斷屬性是否是實(shí)例屬性。其結(jié)果是一個(gè)布爾值, true說明是實(shí)例屬性,false說明不是實(shí)例屬性。in操作符會(huì)在通過對象能夠訪問給定屬性時(shí)返回true,無論該屬性存在于實(shí)例中還是原型中。
類的所有實(shí)例共享一個(gè)原型對象,它們的原型都是Person.prototype,所以proto屬性是相等的
由此,也可以通過proto來為類增加方法。使用實(shí)例的proto屬性改寫原型,會(huì)改變Class的原始定義,影響到所有實(shí)例,所以不推薦使用!
class不存在變量提升,所以需要先定義再使用。因?yàn)镋S6不會(huì)把類的聲明提升到代碼頭部,但是ES5就不一樣,ES5存在變量提升,可以先使用,然后再定義。
4.2 Class 的繼承
Class 可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承,這比 ES5 的通過修改原型鏈實(shí)現(xiàn)繼承,要清晰和方便很多。
4.3 proxy
proxy在目標(biāo)對象的外層搭建了一層攔截,外界對目標(biāo)對象的某些操作,必須通過這層攔截
var proxy = new Proxy(target, handler);
new Proxy()表示生成一個(gè)Proxy實(shí)例,target參數(shù)表示所要攔截的目標(biāo)對象,handler參數(shù)也是一個(gè)對象,用來定制攔截行為
· targetWithLog 讀取屬性的值時(shí),實(shí)際上執(zhí)行的是 logHandler.get :在控制臺輸出信息,并且讀取被代理對象 target 的屬性。
· 在 targetWithLog 設(shè)置屬性值時(shí),實(shí)際上執(zhí)行的是 logHandler.set :在控制臺輸出信息,并且設(shè)置被代理對象 target 的屬性的值
4.4 Proxy的作用
對于代理模式 Proxy 的作用主要體現(xiàn)在三個(gè)方面
- 攔截和監(jiān)視外部對對象的訪問
- 降低函數(shù)或類的復(fù)雜度
- 在復(fù)雜操作前對操作進(jìn)行校驗(yàn)或?qū)λ栀Y源進(jìn)行管理
代碼演示:
本期為大家?guī)淼腤eb前端學(xué)習(xí)知識”Web前端:ES6是干什么的?(下)“介紹完畢了,想了解更多內(nèi)容的小伙伴,關(guān)注我,更多內(nèi)容等你看,我們下期再見!
總結(jié)
以上是生活随笔為你收集整理的前端为什么有的接口明明是成功回调却执行了.catch失败回调_Web前端:ES6是干什么的?(下)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javaweb和ajax使用查询出来的数
- 下一篇: python包安装_Python及图像处