距离上一篇博客书写,又过去了大概几个月了,这段时间暂时离开了这个行业,让大脑休息一下。一个人旅行,一个人休息,正好也去完成一个目标 --- 拥有自己的驾照。当然,也把自己晒的黑漆马虎的。不过这一段时间虽然在技术上没有学太多东西,但是在心态上给了自己一个沉淀的机会,感觉自己变得更加沉稳和成熟,感觉这就是自己需要找到的自己,回归自我。好了,废话不多说了,虽然技术上没有学一些新的东西,但是欠的东西还是要补回来的。正如这篇博客,前端 Promise 规范的实现与 ajax 技术的集成,当时 github 上一个用户提的,既然写了 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);
- }
具体思路如下:
解决浏览器的差异性和兼容性代码
- 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
ie8-11
edge
firefox
360 浏览器
safair
代码已集成 github:https://github.com/GerryIsWarrior/ajax 点颗星星是我最大的鼓励,有什么问题可以博客、邮箱、github 上留言
还有最重要的一点,如果有问题欢迎指出来,我在 github 上维护这个库,这段时间专注于前端的通信技术的研究,ajax 基本完成,马上进入 SSE 推送技术研究状态
研究 Promise 这个内容,研究和参考了很多别人的代码,从高别人的代码中看到了各种问题,然后在自己代码中测试发现和改正。所以没有什么是绝对正确的,我写的可能也有问题,希望大家在研究和发展的基础上一起改进。毕竟对于前端来说,技术更新太快,ES5 ES6 等等一层接一层。还是那句老话,革命尚未成功,同志仍需努力,我和你们同在。
马上又要回去重新找工作了,希望可以找到如意的工作,毕竟为了错开金三银四,希望一切都会好起来。一起加油吧。
来源: http://www.cnblogs.com/GerryOfZhong/p/7096792.html