前端分享----JS異步編程+ES6箭頭函數

前端分享----JS異步編程+ES6箭頭函數


##概述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'
        });
    }
});

 

是否是以爲仍是比較方便簡潔些了。

相關文章
相關標籤/搜索