是異步編程的一種解決方案,比傳統的解決方案(回調函數和事件)更合理和更強大。它由社區最先
出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。node
所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。
有了Promise對象,就能夠將異步操做以同步操做的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的接口,使得控制異步操做更加容易。ajax
1)傳統ajax編程
是一種異步的JavaScript的請求,可以在不影響當前進程的狀況下和後臺進行交互. 1.發起請求 請求的返回時間難以肯定,影響因素比較多,好比網絡延遲 2.監聽(成功,失敗) 經過判斷狀態碼來決定執行那個回調函數 200 ok 404 not found 500 後臺代碼異常 403 無權訪問 304 文檔內容沒有發生改變 3.調用回調函數 完成請求後的處理 $.getJSON('http://120.78.164.247:8080/grade',function(data){ alert(data) }); alert('end'); //先執行end 在彈出data
出現的問題:在回調函數中嵌套若是比較多,就很容易出問題json
2)promise數組
承諾 存在三種狀態: 1.未知狀態, 2.成功狀態,resolve() 未知狀態---》成功狀態 3.失敗狀態,reject() 未知狀態---》失敗狀態 ajax中使用最多 let promise = new Promise((resolve,reject)=>{ $.ajaxSetup({ error:function(){reject()}; //失敗 }); $.get('',function(data){ resolve(data); //成功 }); promise.then(()={}).catch(()=>{});
在個人理解中promise是對ajax的一種封裝,上述代碼中,使用的是用JQuery封裝的ajax代碼分紅了兩部分。promise
let fetch = (method,url,successHandler,errorHandler)=>{ let xhr = new XMLHttpRequest(); xhr.open(method,url); xhr.responseType = 'json'; xhr.setRequestHeader('Accept','application/json');//設置頭部信息 xhr.onreadystatechange = function(){ if(this.readyState == 4){ if(this.status == 200){ successHandler(this.response) }else{ errorHandler(this.response); }; } }; xhr.send(); }
須要注意的是由於原生代碼中須要http協議,因此這個代碼在node中是沒法使用的,服務器
2.下面來看看使用promise來封裝網絡
簡單的思路:app
let promise = new Promise((resolve,reject)=>{ setTimeout(function(){//模擬異步請求 if (Math.round(Math.random()*10)>5) { resolve('success');//成功 }else{ reject('erro');//失敗 } },3000); }); promise.then((data)=>{ console.log(data); }).catch((erro)=>{ console.log(erro); });
咱們來看看promise如何封裝Ajaxdom
let fetch = (method,url)=>{ return new Promise((resolve,reject)=>{ let xhr = new XMLHttpRequest();//聲明一個請求 xhr.open(method,url); xhr.responseType = 'json'; xhr.setRequestHeader('Accept','application/json'); xhr.onreadystatechange = function(){ if(this.readyState == 4){//判斷狀態 if(this.status == 200){ resolve(this.response) }else{ reject(this.response); }; }; }; xhr.send();//發送請求 }); }; fetch('get','http://120.78.164.247:8080/grade/findAll').then(({code,msg,extend})=>{ console.log(code); console.log(msg); console.log(extend); }).catch(()=>{});//調用本身封裝的fetch
接着,咱們來看看Promise中的一些基本用法
1.Promise.prototype.then()
.then(function(){//success},functions(){//error});
then方法是定義在原型對象Promise.prototype上的,也就是說,Promise 實例具備then方法。它的做用是爲 Promise 實例添加狀態改變時的回調函數。then方法的第一個參數是Resolved狀態的回調函數,第二個參數(可選)是Rejected狀態的回調函數。then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。所以能夠採用鏈式寫法,即then方法後面再調用另外一個then方法。若是使用兩個then方法,第一個回調函數完成之後,會將返回結果做爲參數,傳入第二個回調函數。
getJSON("/post/1.json").then( post => getJSON(post.commentURL) ).then( comments => console.log("Resolved: ", comments), err => console.log("Rejected: ", err) );
上面代碼中,第一個then方法指定的回調函數,返回的是另外一個Promise對象。這時,第二個then方法指定的回調函數,就會等待這個新的Promise對象狀態發生變化。若是變爲resolved,就調用funcA,若是狀態變爲rejected,就調用funcB。
Promise.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回調函數,通常來講,不要在then方法裏面定義Reject狀態的回調函數(即then的第二個參數),老是使用catch方法。
var promise = new Promise(function(resolve, reject) { reject(new Error('test')); }); promise.catch(function(error) { console.log(error); });
Promise 對象的錯誤具備「冒泡」性質,會一直向後傳遞,直到被捕獲爲止。也就是說,錯誤老是會被下一個catch語句捕獲。
Promise.all方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。
var p = Promise.all([p1, p2, p3]);
上面代碼中,Promise.all方法接受一個數組做爲參數,p一、p二、p3都是 Promise 實例,p的狀態由p一、p二、p3決定,分紅兩種狀況。
只有p一、p二、p3的狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p一、p二、p3的返回值組成一個數組,傳遞給p的回調函數。
只要p一、p二、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
Promise.race方法一樣是將多個Promise實例,包裝成一個新的Promise實例。下面代碼中,只要p一、p二、p3之中有一個實例率先改變狀態,p的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。
var p = Promise.race([p1, p2, p3]);
上面代碼中,Promise.all方法接受一個數組做爲參數,p一、p二、p3都是 Promise 實例,p的狀態由p一、p二、p3決定,分紅兩種狀況。
只有p一、p二、p3的狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p一、p二、p3的返回值組成一個數組,傳遞給p的回調函數。
只要p一、p二、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
方法將現有對象轉爲Promise對象,例如:
var jsPromise = Promise.resolve($.ajax('/whatever.json'));
根據參數的不一樣,方法的返回值也會發生變化:
1.參數是一個Promise實例 Promise.resolve將不作任何修改、原封不動地返回這個實例。 2.參數是一個thenable對象 thenable對象指的是具備then方法的對象,Promise.resolve方法會將這個對象轉爲Promise對象,而後就當即執行thenable對象的then方法。 3.參數不是具備then方法的對象,或根本就不是對象 若是參數是一個原始值,或者是一個不具備then方法的對象,則Promise.resolve方法返回一個新的Promise對象,狀態爲Resolved。 4.不帶有任何參數 直接返回一個Resolved狀態的Promise對象。須要注意的是,當即resolve的Promise對象,是在本輪「事件循環」(event loop)的結束時,而不是在下一輪「事件循環」的開始時。
Promise.reject(reason)方法也會返回一個新的 Promise 實例,該實例的狀態爲rejected 。
var p = Promise.reject('出錯了'); // 等同於 var p = new Promise((resolve, reject) => reject('出錯了')) ;
finally方法用於指定無論Promise對象最後狀態如何,都會執行的操做。它接受一個普通的回調函數做爲參數,該函數無論怎樣都必須執行。
下面是一個例子,服務器使用Promise處理請求,而後使用finally方法關掉服務器
server.listen(0) .then(function () { // run test }) .finally(server.stop); //關掉服務器
Promise對象的使用大體分爲以下幾個步驟:
1. 構建承諾對象 let promise = new Promise((resolve,reject)=>{ // resolve() 未知->成功 // reject() 未知->失敗 }); 2. 執行 promise.then(()=>{ //成功後的回調 }).catch(()=>{ //失敗後的回調 }); 3. 企業級應用