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