##概述Javascript語言的執行環境是"單線程"(single thread)。所謂"單線程",就是指一次只能完成一件任務。若是有多個任務,就必須排隊,前面一個任務完成,再執行後面一個任務。前端
這種模式的好處是實現起來比較簡單,執行環境相對單純;壞處是隻要有一個任務耗時很長,後面的任務都必須排隊等着,會拖延整個程序的執行。常見的瀏覽器無響應(假死),每每就是由於某一段Javascript代碼長時間運行(好比死循環),致使整個頁面卡在這個地方,其餘任務沒法執行。java
JavaScript語言自己並不慢,慢的是讀寫外部數據,好比等待Ajax請求返回結果。這個時候,若是對方服務器遲遲沒有響應,或者網絡不通暢,就會致使腳本的長時間停滯。ajax
爲了解決這個問題,Javascript語言將任務的執行模式分紅兩種:同步(Synchronous)和異步(Asynchronous)。"同步模式"就是傳統作法,後一個任務等待前一個任務結束,而後再執行,程序的執行順序與任務的排列順序是一致的、同步的。這每每用於一些簡單的、快速的、不涉及讀寫的操做。編程
"異步模式"則徹底不一樣,每個任務分紅兩段,第一段代碼包含對外部數據的請求,第二段代碼被寫成一個回調函數,包含了對外部數據的處理。第一段代碼執行完,不是馬上執行第二段代碼,而是將程序的執行權交給第二個任務。等到外部數據返回了,再由系統通知執行第二段代碼。因此,程序的執行順序與任務的排列順序是不一致的、異步的。promise
如下總結了"異步模式"編程的幾種方法,理解它們可讓你寫出結構更合理、性能更出色、維護更方便的JavaScript程序。##實際應用場景在項目的編輯頁面,有不少時候會出現下拉,而且下拉框是經過請求後臺獲取的數據,可是會出現一種狀況你們可能有遇到過,就是下拉框回填不成功,可能你們已經都清楚了緣由就是由於:當請求的詳情信息還沒返回,請求的下拉接口卻已經先返回來了,說直白一點,就是程序的執行前後順序問題。那麼怎麼解決這種問題呢?##常見的解決方案###1.用延時來推測結果大概何時!瀏覽器
var result=ajax(url); setTimeout(function(result){ console.log(result); },400);
優勢:幾乎無弊端:儘可能可能設置長時間延時,不然,咱們將會操做一個undefined的result,能夠說這是一種最不推薦而且反對的寫法###2.回調函數!js最多見的一種規定程序執行的前後順序的處理就是採用回調函數,可能java的同窗不是很明白,其實不少地方都應用到了,好比:ajax的成功以後調用success方法,失敗調用error方法,這種就叫回調函數,在某個時間點,數據返回來了,就執行。因此,一般遇到實際場景就會採用回調函數的寫法,把第二個ajax寫在第一個ajax的success裏面,等第一個ajax請求返回結果後,在執行第二個。這種方法俗稱函數嵌套。能解決這種狀況。可是既然叫函數嵌套,嵌套二字不免讓人感受冗餘,沒錯。服務器
ajax(url0,function(result0){ ajax(result0.url1,function(result1){ ajax(result1.url2,function(result2){ console.log(result2); }); }); });
若是嵌套有3個甚至更多,那就出現了回調地獄(Callback Hell)問題。如何規避這種問題呢?答案是就是:promise/a+規範,下面咱們看一下promise/a+規範在瞭解promise以前咱們先來了解一個鏈式寫法;##鏈式寫法鏈式寫法也是咱們在使用jQuery時候常見的一種,網絡
$('#tab').eq($(this).index()).show().siblings().hide();
沒錯,這個就是咱們所謂的鏈式寫法,只是你們不知道書名而已;之因此叫鏈式寫法,不難看出咱們在一個元素上作的全部jQuery處理均可以一直 "." 下去, 爲何能這樣,由於jQuery源碼封裝的時候,每一個方法都返回this(jQuery)。dom
var obj = { step1:function(){ console.log('a'); return this; }, step2:function(){ console.log('b'); return this; }, step3:function(){ console.log('c'); return this; }, step4:function(){ console.log('d'); return this; } } console.log('-----\n'); obj.step1().step2().step3(); console.log('-----\n'); obj.step4().step2().step1();
執行結果複製到控制檯查看。這樣的寫法是否是看着很爽,那麼與咱們要講的promise有什麼關係呢?下面進入主題PromiseES 6中原生提供了Promise對象,Promise對象表明了某個將來纔會知道結果的事件(通常是一個異步操做),而且這個事件對外提供了統一的API,可供進一步處理。Promise對象有三種狀態,分別是pending-進行中、resolved-已完成、rejected-已失敗當Promise的狀態由pending轉變爲resolved或rejected時,會執行相應的方法,而且狀態一旦改變,就沒法再次改變狀態,這也是它名字promise-承諾的由來。Promise的構造函數接受一個函數做爲參數,這個函數的兩個參數分別是resolve方法和reject方法。若是異步操做成功,就是用resolve方法將Promise對象的狀態從「未完成」變爲「完成」(即從pending變爲resolved),若是異步操做出錯,則是用reject方法把Promise對象的狀態從「未完成」變爲「失敗」(即從pending變爲rejected)異步
###Promise.prototype.then()Promise的then方法返回的是一個新的Promise對象,因此這樣呢,咱們就能鏈式操做了,同時then方法它包含兩個參數方法,分別是已成功resolved的回調和已失敗rejected的回調,分別是狀態看一個例子吧!
const p = function(){ let num = Math.random(); return new Promise((resolve, reject) => { setTimeout(() => { num > 0.1 ? resolve(num) : reject(num); }, 1000); }) }; const p1 = function(val){ let num = Math.random(); return new Promise((resolve, reject) => { setTimeout(() => { num > 0.01 ? resolve(num) : reject(num); }, 1000); }) }; p().then(val => { console.info(`Status1:fulfilled, value1:${val}`); return p1(val); }, val => { console.info(`Status1:reject,value1:${val}`); }).then(val => { console.info(`Status2:fulfilled, value2:${val}`); }, /*function(val1){console.log(val1); },*/val => { console.info(`Status2:reject,value2:${val}`); })
那麼每一個then方法都要寫一個成功的方法和失敗的方法貌似有點冗餘啊,還好,Promise提供了一個catch()方法,.catch()的做用是捕獲Promise的錯誤,與then()的rejected回調做用幾乎一致,因爲Promise的拋錯具備冒泡性質,可以不斷傳遞,這樣就可以在下一個catch()中統一處理這些錯誤。同時catch()也可以捕獲then()中拋出的錯誤,因此建議不要使用then()的rejected回調,而是統一使用catch()來處理錯誤。因此上面代碼改成
p().then(val => { console.info(`Status1:fulfilled, value1:${val}`); return p1(val); }).then(val => { console.info(`Status2:fulfilled, value2:${val}`); }).catch(function(err) { console.log('出錯:' + err); // 出錯:reject // 最後的catch()方法能夠捕獲在這一條Promise鏈上的異常 })
好了!大家下來能夠試着去這樣用用Promise。
##ES6箭頭函數一個常見的問題是,ECMAScript 和 JavaScript 究竟是什麼關係?不是很重要,因此直白一點,ECMAScript 和 JavaScript 的關係是,前者是後者的規格,後者是前者的一種實現。而ES6,就是ECMAScript的一個版本而已,於2015年發佈初版。
1.具備一個參數的簡單函數
var f = v => v; //上面的箭頭函數等同於: var f = function(v) { return v; };
2.沒有參數的須要用在箭頭前加上小括號
//若是箭頭函數不須要參數或須要多個參數,就使用一個圓括號表明參數部分。
var f = () => 5; // 等同於 var f = function () { return 5 };
3.多個參數須要用到小括號,參數間逗號間隔,例如兩個數字相加
//若是箭頭函數不須要參數或須要多個參數,就使用一個圓括號表明參數部分。 var sum = (num1, num2) => num1 + num2; // 等同於 var sum = function(num1, num2) { return num1 + num2; };
4.函數體多條語句須要用到大括號
var add = (a, b) => { if (typeof a == 'number' && typeof b == 'number') { return a + b } else { return 0 } }
5.返回對象時須要用小括號包起來,由於大括號被佔用解釋爲代碼塊了
var getHash = arr => {({ name: 'Jack', age: 33 })}
再多囉嗦一個東西:解構賦值
requestLogin(loginParams).then(data => { this.logining = false; let { msg, code, user, list} = data; if (!list.length) { this.$message({ message: '登陸失敗', type: 'error' }); } }); //等同於 requestLogin(loginParams).then(data => { var msg=data.msg; var list=data.list; var code=data.code; if (!list.length) { this.$message({ message: '登陸失敗', type: 'error' }); } });
是否是以爲仍是比較方便簡潔些了。