前端通信: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);
}

具体思路如下:

 

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

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

 

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

目录
相关文章
|
9月前
|
机器学习/深度学习 算法 物联网
面向能效和低延迟的语音控制智能家居:离线语音识别与物联网集成方案——论文阅读
本文提出一种面向能效与低延迟的离线语音控制智能家居方案,通过将关键词识别(KWS)集成至终端设备,结合去中心化Mesh网络与CoAP协议,实现本地化语音处理。相较云端方案,系统能耗降低98%,延迟减少75%以上,显著提升响应速度与能源效率,为绿色智能家居提供可行路径。(236字)
828 17
面向能效和低延迟的语音控制智能家居:离线语音识别与物联网集成方案——论文阅读
编解码 算法 vr&ar
663 0
|
10月前
|
自然语言处理 负载均衡 算法
推理速度提升300%:LLaMA4-MoE的FlashAttention-2集成与量化部署方案
本文详解LLaMA4-MoE模型架构与实现全流程,涵盖语料预处理、MoE核心技术、模型搭建、训练优化及推理策略,并提供完整代码与技术文档,助你掌握大模型MoE技术原理与落地实践。
580 6
|
11月前
|
缓存 人工智能 监控
MCP资源管理深度实践:动态数据源集成方案
作为一名深耕AI技术领域多年的开发者,我见证了从传统API集成到现代化协议标准的演进历程。今天要和大家分享的MCP(Model Context Protocol)资源管理实践,是我在实际项目中积累的宝贵经验。MCP作为Anthropic推出的革命性AI连接标准,其资源管理机制为我们提供了前所未有的灵活性和扩展性。在过去的几个月里,我深度参与了多个企业级MCP项目的架构设计和实施,从最初的概念验证到生产环境的大规模部署,每一个环节都让我对MCP资源管理有了更深刻的理解。本文将从资源生命周期管理的角度出发,详细探讨文件系统、数据库、API等多种数据源的适配策略,深入分析实时数据更新与缓存的最佳实践
379 0
|
11月前
|
人工智能 安全 API
MCP vs 传统集成方案:REST API、GraphQL、gRPC的终极对比
作为一名长期关注AI技术发展的博主摘星,我深刻感受到了当前AI应用集成领域正在经历的巨大变革。随着Anthropic推出的Model Context Protocol(MCP,模型上下文协议)逐渐成熟,我们不得不重新审视传统的系统集成方案。在过去的几年中,REST API凭借其简单易用的特性成为了Web服务的标准选择,GraphQL以其灵活的数据查询能力赢得了前端开发者的青睐,而gRPC则以其高性能的特点在微服务架构中占据了重要地位。然而,当我们将视角转向AI应用场景时,这些传统方案都暴露出了一些局限性:REST API的静态接口设计难以适应AI模型的动态需求,GraphQL的复杂查询机制在处
567 0
MCP vs 传统集成方案:REST API、GraphQL、gRPC的终极对比
|
11月前
|
JSON API 开发者
Django集成Swagger全指南:两种实用方案详解
本文介绍了在 Django 项目中集成 Swagger 的两种主流方案 —— drf-yasg 和 drf-spectacular,涵盖安装配置、效果展示及高级用法,助力开发者高效构建交互式 API 文档系统,提升前后端协作效率。
459 5
|
12月前
|
存储 Kubernetes 监控
Docker与Kubernetes集成挑战及方案
面对这些挑战,并不存在一键解决方案。如同搭建灌溉系统需要考虑多种因素,集成Docker与Kubernetes也需要深思熟虑的规划、相当的技术知识和不断的调试。只有这样,才能建立起一个稳定、健康、高效的Docker-Kubernetes生态,让你的应用像花园中的植物一样繁荣生长。
448 63
|
人工智能 BI API
Dify-Plus:企业级AI管理核弹!开源方案吊打SaaS,额度+密钥+鉴权系统全面集成
Dify-Plus 是基于 Dify 二次开发的企业级增强版项目,新增用户额度、密钥管理、Web 登录鉴权等功能,优化权限管理,适合企业场景使用。
2112 3
Dify-Plus:企业级AI管理核弹!开源方案吊打SaaS,额度+密钥+鉴权系统全面集成
|
机器学习/深度学习 人工智能 自然语言处理
企业级API集成方案:基于阿里云函数计算调用DeepSeek全解析
DeepSeek R1 是一款先进的大规模深度学习模型,专为自然语言处理等复杂任务设计。它具备高效的架构、强大的泛化能力和优化的参数管理,适用于文本生成、智能问答、代码生成和数据分析等领域。阿里云平台提供了高性能计算资源、合规与数据安全、低延迟覆盖和成本效益等优势,支持用户便捷部署和调用 DeepSeek R1 模型,确保快速响应和稳定服务。通过阿里云百炼模型服务,用户可以轻松体验满血版 DeepSeek R1,并享受免费试用和灵活的API调用方式。
905 12
|
DataWorks 数据挖掘 大数据
方案实践测评 | DataWorks集成Hologres构建一站式高性能的OLAP数据分析
DataWorks在任务开发便捷性、任务运行速度、产品使用门槛等方面都表现出色。在数据处理场景方面仍有改进和扩展的空间,通过引入更多的智能技术、扩展数据源支持、优化任务调度和可视化功能以及提升团队协作效率,DataWorks将能够为企业提供更全面、更高效的数据处理解决方案。

热门文章

最新文章

  • 1
    前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
    1170
  • 2
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(九):强势分析Animation动画各类参数;从播放时间、播放方式、播放次数、播放方向、播放状态等多个方面,完全了解CSS3 Animation
    514
  • 3
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(八):学习transition过渡属性;本文学习property模拟、duration过渡时间指定、delay时间延迟 等多个参数
    400
  • 4
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(七):学习ransform属性;本文学习 rotate旋转、scale缩放、skew扭曲、tanslate移动、matrix矩阵 多个参数
    396
  • 5
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(六):全方面分析css的Flex布局,从纵、横两个坐标开始进行居中、两端等元素分布模式;刨析元素间隔、排序模式等
    511
  • 6
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(五):背景属性;float浮动和position定位;详细分析相对、绝对、固定三种定位方式;使用浮动并清除浮动副作用
    684
  • 7
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(四):元素盒子模型;详细分析边框属性、盒子外边距
    1218
  • 8
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(三):元素继承关系、层叠样式规则、字体属性、文本属性;针对字体和文本作样式修改
    275
  • 9
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
    1013
  • 10
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(一):CSS发展史;CSS样式表的引入;CSS选择器使用,附带案例介绍
    473