该迭代已作废,最新的请移步这里:https://www.cnblogs.com/GerryOfZhong/p/10726306.html

距离上一篇博客书写,又过去了大概几个月了,这段时间暂时离开了这个行业,让大脑休息一下。一个人旅行,一个人休息,正好也去完成一个目标 --- 拥有自己的驾照。当然,也把自己晒的黑漆马虎的。不过这一段时间虽然在技术上没有学太多东西,但是在心态上给了自己一个沉淀的机会,感觉自己变得更加沉稳和成熟,感觉这就是自己需要找到的自己,回归自我。好了,废话不多说了,虽然技术上没有学一些新的东西,但是欠的东西还是要补回来的。正如这篇博客,前端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);
}

具体思路如下:

解决浏览器的差异性和兼容性代码

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(); //挂起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等等一层接一层。还是那句老话,革命尚未成功,同志仍需努力,我和你们同在。

马上又要回去重新找工作了,希望可以找到如意的工作,毕竟为了错开金三银四,希望一切都会好起来。一起加油吧。

前端通信:ajax设计方案(五)--- 集成promise规范,更优雅的书写代码(改迭代已作废,移步迭代10)的更多相关文章

  1. 框架基础:ajax设计方案(五)--- 集成promise规范,更优雅的书写代码

    距离上一篇博客书写,又过去了大概几个月了,这段时间暂时离开了这个行业,让大脑休息一下.一个人旅行,一个人休息,正好也去完成一个目标 --- 拥有自己的驾照.当然,也把自己晒的黑漆马虎的.不过这一段时间 ...

  2. 前端通信:ajax设计方案(十)--- 完善Promise A+规范,增加mock数据功能

    半年不迭代,迭代搞半年,说的就是我,这里有点尴尬了,直接进入主题吧 我记得在这篇博客的时候集成了Promise的,不过那个时候就简简单单的写了一点最基础,在一些特殊的case上,还是有点问题的,所以才 ...

  3. 前端通信:ajax设计方案(三)--- 集成ajax上传技术

    在此之前让我感慨一下现在的前端开发的氛围.我遇到好多人,给我的观念都是,这个东西这个框架有了,那个东西那个框架做了,前端嘛,学几个框架,这个拼凑一下那个拼凑一下就好了.其实我想问,东西都框架做了,那你 ...

  4. 前端通信:ajax设计方案(四)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组

    马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...

  5. 前端通信:ajax设计方案(一)---集成核心请求

    报告,我要说话!xp被历史淘汰了,IE6 say goodbye了,太TM开心了,从此不要兼容IE6了,哈哈哈哈哈哈 报告,我要说话!IE这sb为啥不早点被杀掉呢,找工作听说要兼容IE,立马软了,唉唉 ...

  6. 前端通信:ajax设计方案(六)--- 全局配置、请求格式拓展和优化、请求二进制类型、浏览器错误搜集以及npm打包发布

    距离上一次博客大概好多好多时间了,感觉再不搞点东西出来,感觉就废了的感觉.这段时间回老家学习驾照,修养,然后7月底来上海求职(面了4家,拿了3家office),然后入职同程旅游,项目赶进度等等一系列的 ...

  7. 框架基础:ajax设计方案(三)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组

    马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...

  8. 前端通信:ajax设计方案(八)--- 设计请求池,复用请求,让前端通信快、更快、再快一点

    直接进入主题,本篇文章有点长,包括从设计阶段,到摸索阶段,再到实现阶段,最后全面覆盖测试阶段(包括数据搜集清洗),还有与主流前端通信框架进行对比PK阶段. 首先介绍一下一些概念: 1. 浏览器的并发能 ...

  9. 框架基础:ajax设计方案(三)---集成ajax上传技术

    之前发布了ajax的通用解决方案,核心的ajax发布请求,以及集成了轮询.这次去外国网站逛逛,然后发现了ajax level2的上传文件,所以就有了把ajax的上传文件集成进去的想法,ajax方案的l ...

随机推荐

  1. JSTL安装与使用

    第一步:下载支持JSTL的文件.jakarta-taglibs-standard-1.1.2.zip 第二步:下载解压后的两个jar文件:standard.jar和jstl.jar文件拷贝到工程的\W ...

  2. (最大m子段和) Max Sum Plus Plus (Hdu 1024)

    http://acm.hdu.edu.cn/showproblem.php?pid=1024     Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/ ...

  3. POJ2594 Treasure Exploration(最小路径覆盖)

    Treasure Exploration Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 8550   Accepted: 3 ...

  4. python_条件语句

    条件语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. Python程序语言指定任何非0和非空(null)值为true,0 或者 null为fals ...

  5. Vue的配置

    一.build:打包的配置文件的文件夹 1.build.js  生产版本的配置文件,一般这个文件我们是不改的 'use strict' //调用检查版本的文件,check-versions的导出直接是 ...

  6. AngularJS 过滤器 Filter

    过滤器实质是数据转换或过滤,把ViewMode中的数据转化成View层用户友好的信息.可以看做一个函数,负责接收输入,转换成输出,每次参数变化时,它就被执行,输出被视图View使用. 一.基本定义及其 ...

  7. 1.虚拟机中安装ubuntu

    1.VMware安装很简单,全部默认安装即可. 2.安装完VMware之后,打开VMware,点击创建虚拟机 典型安装易出问题,所以这里选择自定义安装 安装过程选项配置如下 处理器数,核数,内存都可以 ...

  8. Python--多线程处理

    python中有好几种多线程处理方式,更喜欢使用isAlive()来判断线程是否存活,笔记一下,供以后查找 # coding: utf-8 import sys, time import thread ...

  9. net 把指定 URI 的资源下载到本地

    DirectoryInfo dir = new DirectoryInfo(AppContext.BaseDirectory); var path = dir.FullName + @"te ...

  10. 由VC2010与VC2017数据结构差异造成的程序错误

    内容:VC2010和VC2017的标准库中,string(或wstring)的数据结构和操作有所不同,所以在将这两种数据作为参数在两个系统产生的函数中传递时会出现乱码(string和wstring在2 ...