當前位置:
首頁 > 知識 > 框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

距離上一篇博客書寫,又過去了大概幾個月了,這段時間暫時離開了這個行業,讓大腦休息一下。一個人旅行,一個人休息,正好也去完成一個目標 --- 擁有自己的駕照。當然,也把自己曬的黑漆馬虎的。不過這一段時間雖然在技術上沒有學太多東西,但是在心態上給了自己一個沉澱的機會,感覺自己變得更加沉穩和成熟,感覺這就是自己需要找到的自己,回歸自我。好了,廢話不多說了,雖然技術上沒有學一些新的東西,但是欠的東西還是要補回來的。正如這篇博客,前端Promise規範的實現與ajax技術的集成,當時github上一個用戶提的,既然寫了ajax,那麼Promise的規範,更優雅的操作非同步也應該有的,當時記下了,現在補回來。回歸正題,下面介紹一些概念。

  • Promise

    ES6中最重要的特性之一,就是代表了未來某個將要發生的事件(通常是一個非同步操作)。它的好處在於,有了Promise對象,就可以將非同步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。
  • js對象的繼承和傳遞

    在js中是沒有所謂的繼承概念的,繼承通常是指後檯面向對象編程中對象之間的復用。因為js被叫做腳本語言,所以沒有這個概念,但是在js中都可以模擬實現的(apply,call,prototype)。其實說通俗點所謂的繼承就是作用域的傳遞。
  • ajax和promise的緣分

    因為ajax是一個非同步的請求(雖然也可以使用同步),而promise這個狀態機也正好可以處理非同步操作。兩者的相結合的產物,將是一個優雅而又快捷的產物,這個將在後面的介紹中展現。

工具準備:

1. 前端代碼,自己實現的promise規範代碼,以及集成現有es6規範的代碼。

2. nginx伺服器,做分離,反向代理後台代碼

3. IIS伺服器,部署後台請求(模擬一般請求和高延遲請求)

4. 各大兼容和不兼容promise的瀏覽器(做測試)

前端Promise代碼實現:

/**
* Created by gerry.zhong on 2017/6/21.
*/
var Promise = function(fn){
var promise = this;
//狀態機的狀態
var PROMISESTATE = {
PENDING : 0 ,
FULFILLED : 1 ,
REJECTED : 2
};
//存儲當前變數的回調函數和標記對象為promise
promise._fullCalll =,promise._rejCall = ;promise._name = "promise";
//執行過程中的狀態變化(初始化狀態為默認狀態)
var _state = PROMISESTATE.PENDING;
//回調函數的參數
var _value = undefined;

//狀態變更
function setState(stateT,valueT){
var promise = this;
_state = stateT;
_value = valueT;
handleFun.call(promise); //傳遞作用域,並且執行回調函數
};

//根據狀態處理回調
function handleFun{
var promise = this,isThen;

if (_state === PROMISESTATE.FULFILLED &&
typeof promise._fullCalll[0] === "function") {
isThen = promise._fullCalll[0](_value);
};
if (_state === PROMISESTATE.REJECTED &&
typeof promise._rejCall[0] === "function") {
isThen = promise._rejCall[0](_value);
};
//對於是否可以繼續進行then做判斷
// 1. 不可then的,直接return結束(條件:無返回值、返回值不是promise對象的)
// 2. 對於可以then的,將then的回調進行處理,然後對象之間傳遞。
if (isThen === undefined || !(typeof isThen === "object" && isThen._name === "promise")) return;

promise._fullCalll.shift; promise._rejCall.shift; //清除當前對象使用過的對調
isThen._fullCalll =promise._fullCalll;isThen._rejCall = promise._rejCall; //將剩下的回調傳遞到下一個對象
};

//promimse入口
function doResolve(fn){
var promise = this;
fn(function(param) {
setState.call(promise,PROMISESTATE.FULFILLED,param);
}, function(reason) {
setState.call(promise,PROMISESTATE.REJECTED,reason);
});
};

//函數then,處理回調,返回對象保證鏈式調用
this.then = function(onFulfilled,onRejected) {
this._fullCalll.push(onFulfilled);
this._rejCall.push(onRejected);
return this;
}

doResolve.call(promise,fn);
}

具體思路如下:

框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

解決瀏覽器的差異性和兼容性代碼

if (!window.Promise) tool.createPromise; //保證瀏覽器的兼容性

tool.createPromise代碼

//如果瀏覽器不支持Promise特性,將用簡易的promise代替(IE11-都不支持ES6 Promise)
createPromise:function{
var newPromise = function(fn){
var promise = this;
//狀態機的狀態
var PROMISESTATE = {
PENDING : 0 ,
FULFILLED : 1 ,
REJECTED : 2
};
//存儲當前變數的回調函數和標記對象為promise
promise._fullCalll =,promise._rejCall = ;promise._name = "promise";
//執行過程中的狀態變化(初始化狀態為默認狀態)
var _state = PROMISESTATE.PENDING;
//回調函數的參數
var _value = undefined;

//狀態變更
function setState(stateT,valueT){
var promise = this;
_state = stateT;
_value = valueT;
handleFun.call(promise); //傳遞作用域,並且執行回調函數
};

//根據狀態處理回調
function handleFun{
var promise = this,isThen;

if (_state === PROMISESTATE.FULFILLED &&
typeof promise._fullCalll[0] === "function") {
isThen = promise._fullCalll[0](_value);
};
if (_state === PROMISESTATE.REJECTED &&
typeof promise._rejCall[0] === "function") {
isThen = promise._rejCall[0](_value);
};
//對於是否可以繼續進行then做判斷
// 1. 不可then的,直接return結束(條件:無返回值、返回值不是promise對象的)
// 2. 對於可以then的,將then的回調進行處理,然後對象之間傳遞。
if (isThen === undefined || !(typeof isThen === "object" && isThen._name === "promise")) return;

promise._fullCalll.shift; promise._rejCall.shift; //清除當前對象使用過的對調
isThen._fullCalll =promise._fullCalll;isThen._rejCall = promise._rejCall; //將剩下的回調傳遞到下一個對象
};

//promimse入口
function doResolve(fn){
var promise = this;
fn(function(param) {
setState.call(promise,PROMISESTATE.FULFILLED,param);
}, function(reason) {
setState.call(promise,PROMISESTATE.REJECTED,reason);
});
};

//函數then,處理回調,返回對象保證鏈式調用
this.then = function(onFulfilled,onRejected) {
this._fullCalll.push(onFulfilled);
this._rejCall.push(onRejected);
return this;
}

doResolve.call(promise,fn);
};
window.Promise = newPromise;
},

這樣就保證了,不管在兼容和不兼容Promise的瀏覽器中,都可以使用Promise,優雅的來操作非同步了。

ajax集成proise代碼(默認只開放了post和get方法,其他可自己拓展)

     //集成promise的ajax請求(默認設置post和get請求,如有其他需求,可自己拓展)
promiseAjax:function (url,data,type){
if (!window.Promise) tool.createPromise; //保證瀏覽器的兼容性
return new Promise(function(resolve, reject){
if (type === undefined) ajax.post(url,data,resolve,reject);
else ajax.get(url,data,resolve,reject);
});
},

測試環節

對於網上很多人寫的Promise代碼仔細觀摩和研究,發現很多問題。

a. 對於並發Promise,會出現非同步錯亂,發起者和接受者錯亂

b. 對於多then的情況,非同步響應的不確定(高低延遲),錯亂。

c. Promise代碼實現的複雜性,多繁瑣,難理解,思路不明確。

針對以上問題,進行重要測試。

測試前端代碼

ajax.promiseAjax("api/ajax/postReq/",{"name":"q","age": 2})
.then(function(value){
console.log("一般請求q"+value);
return ajax.promiseAjax("api/ajax/postReqSleep/",{"name":"w","age": 2});
})
.then(function(value){
console.log("高延遲請求w:"+value);
return ajax.promiseAjax("api/ajax/postReq/",{"name":"r","age": 2});
})
.then(function(value){
console.log("一般請求r:"+value);
});

ajax.promiseAjax("api/ajax/postReqSleep/",{"name":"q1","age": 2})
.then(function(value){
console.log("高延遲請求q1"+value);
return ajax.promiseAjax("api/ajax/postReqSleep/",{"name":"w2","age": 2});
})
.then(function(value){
console.log("高延遲請求w2:"+value);
return ajax.promiseAjax("api/ajax/postReq/",{"name":"r3","age": 2});
})
.then(function(value){
console.log("一般請求r3:"+value);
});

後端模擬延遲請求代碼(C#)

[Route("postReqSleep")]
public string postRequestTSleep([FromBody]Param param)
{
Thread.Sleep(5000); //掛起5s 做延遲
String result = "post請求成功:" + param.name + "-" + param.age;
return result;
}

測試結果:

chrome

框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

ie8-11

框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

edge

框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

firefox

框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

360瀏覽器

框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

safair

框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

代碼已集成github:https://github.com/GerryIsWarrior/ajax點顆星星是我最大的鼓勵,有什麼問題可以博客、郵箱、github上留言

還有最重要的一點,如果有問題歡迎指出來,我在github上維護這個庫,這段時間專註於前端的通信技術的研究,ajax基本完成,馬上進入SSE推送技術研究狀態

研究Promise這個內容,研究和參考了很多別人的代碼,從高別人的代碼中看到了各種問題,然後在自己代碼中測試發現和改正。所以沒有什麼是絕對正確的,我寫的可能也有問題,希望大家在研究和發展的基礎上一起改進。畢竟對於前端來說,技術更新太快,ES5 ES6等等一層接一層。還是那句老話,革命尚未成功,同志仍需努力,我和你們同在。

馬上又要回去重新找工作了,希望可以找到如意的工作,畢竟為了錯開金三銀四,希望一切都會好起來。一起加油吧。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

「HK」的日常之ARP斷網攻擊
使用kuberspay無坑安裝生產級Kubernetes集群
日常API之百度翻譯
開源自動化測試框架安裝部署
DOCKER 從入門到放棄(一)

TAG:科技優家 |

您可能感興趣

Adidas Superstar周年紀念版包裝設計
全球包裝與設計:Jack Daly-Design/Illustration/Art Direction
Supremexvans「綠頭骨」設計曝光,Adidas推Yeezy替代品
設計師 Khairul Fikri 的字體設計
adidas Originals Prophere 全新配色設計
幻想世界 | 插畫設計師 Eli(quest_bread ) ?
設計師打造 Virgil Abloh x Air Jordan 1 x Balenciaga 三方客制聯乘
Résonances de CartierⅡ:延續Cartier的多個傳統設計主題
Brad Flaherty創意英文字體設計欣賞
深度了解繆繆 (Miu Miu) 、普拉達 (Prada) 女裝總設計師Antonio Fontana:藝術家的一顆私心!
設計手繪JoshuaVidesxAirForce1lowIhandpainted
Outlook.com beta版「人脈」獲全新設計
Arboles Magicos精美畫冊設計欣賞
Reebok Pump Supreme Premium 全新配色設計
The Shoe Surgeon 打造 Virgil Abloh x Air Jordan 1 白色版定製設計
簽約設計師-Suzanne Kasler
Norman Foster x Stelton 限量版設計師餐具系列
新品virgil abloh設計師主理品牌Off-white Arrow detail Low Sneakers
設計師的家「Jonathan Richards」
Horse House圖案設計