前言

  在js领域,promise出现的时间已经很久了,从jquery的$.get().done().fail() 这样的API开始,到现在的es6默认支持的new Promise(),它的出现无疑使异步代码变得信任可靠,更使得前端代码的信任度直线提升,就跟它的名字一样,它的到来,是一个 Promise (保证,允诺)

异步信任问题

  有一个朋友在银行系统工作,有一次,我帮他review一段代码,据他所说,这段代码给他带来了一个很大的麻烦,有一位顾客使用这个页面付款的时候意外的提交了两次付款请求,boss复查发现提交的源头是前端,当我接到这段代码的时候,这位朋友已经焦头烂额,我接过了代码, 初步分析,什么也没发现,他的代码就像下面这样:

$("btn").on("click",function(){
if($(this).hasClass("no-submit")){
$(this).removeClass("no-submit");
//忽略
$.ajax({
url:"....",
type:"json",
success:function(){
submit();
}
})
}
})

他告诉我,他已经针对按钮做点击唯一提交了,怎么可能调用两次?

但是事实就是有两次submit。

通过分析代码,最后排查的结果,原因是这个jquery的$.ajax是被二次封装过的,某种情况下回调函数被调用了两次。

oh,看起来很简单的原因,这可是个巨坑! 日常代码中,我们都需要接触各种各样的第三方库,谁来保证它们都没有隐藏的问题?如果你遇到了经过加密混淆的库,因为它内部某个try catch,或者内部某个if在非正常情况下发成的误判导致重复调用,我想你就不会再淡定的喝着咖啡敲代码了。

或者你觉得,防止重复调用这个很简单,加个判断就行了:

var a = 0;
$("btn").on("click",function(){
if($(this).hasClass("no-submit")){
$(this).removeClass("no-submit");
//忽略
$.ajax({
url:"....",
type:"json",
success:function(){
if( a==0){
submit();
} }
})
}
})

完美是吧,测试上线,继续喝咖啡。

三个月后。。。。。

有些顾客反应,点击提交后,有时没有提交成功,老板这时大发雷霆,这已经是第二次出现这样的失误了。

是的,只调用一次,但是鬼知道它会不会调用一次?

这里问题的本质是什么?

它就是所谓的回调地域。

我们总是有很多的回调函数需要交给第三方工具处理,类似于$.ajax,jquery就一定是值得信任的?图样图森破!你永远不知道jquery下面可能还埋着上一位开发者给你准备的周年大礼包。最糟糕的是,这个第三方工具你没有修改的能力,要么你换掉他,要么你解密,要么换版本,谁知道作者会不会继续更新?

把我们的回调交给不受信任的第三方程序,这就是回调地域,可怕的很!

Promise调用方式

  今天的主角是promise。它可以让我们的回调变得promise。

试想,我们把上述的ajax再次封装(在不能改动源代码的情况下),可能代码如下:

 var then = function(resolve,reject,timeout){
var a = 0;
$("btn").on("click",function(){
if($(this).hasClass("no-submit")){
$(this).removeClass("no-submit");
//忽略
$.ajax({
url:"....",
type:"json",
success:function(){
a==0&&resolve();
a++;
},
error:function(){
a==0&&reject();
a++;
}
})
}
})
if(new Date.now()>timeout){
a==0&&reject();
a++;
}
}
var a = 0;

ok,我只是将前面的代码封装到一个叫then的函数里,这个函数需要三个参数,resolve(解决),reject(拒绝),以及一个超时时间,另外控制调用次数的变量a也有保留。

有什么不同?

不同之处在于,then函数是可信任的,至少现在我们可以确定,它要么被resolve,要么reject,绝不可能出现调用两次,或者不调用的情况。这种封装可以叫做控制反转,

我们将原本给到$.ajax的回调权再次交回自己手中,上面的代码调用起来是这样的:

then(function(){
submit()
},function(){
error()
})

ok,我们只解决了其中的一些问题,重复调用,不调用,但还有更多的问题。

让promise登场吧!

使用promise封装上面代码:

 function request(){
return new Promise(function(resolve,reject){
$.ajax({
url:"....",
type:"json",
success:function(){
resolve()
},
error:function(){
reject()
}
})
})
}
request.then(function(){
submit();
},function(){
error();
})

ok,是否豁然开朗?

promise就是解决关于异步回调信任,顺便缓解了回调金字塔(一堆回调嵌套在一起,就是一个回调金字塔)问题的解决方案。

在这个Promise构造函数中传入一个函数,这个函数有两个值,resolve、reject。一旦代码请求成功,resolve被调用,决议完成并忽略后面的所有调用。或者失败后决议被拒绝,调用reject。

决议、解决、拒绝术语

  一个promise通常有三种状态  pending(进行中)、fulfilled(已成功)和rejected(已失败)。

可以说在任何情况下,一个promise只有一个决议。 它只可能是fulfilled或者rejected其中一种,并且是不可以逆转的。意思是你无法让一个已经被拒绝的promise回滚。它永远都会有一个确定的回复。

   

Promise API

  promise.all(Array);

   Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例,并且这个新的promise返回的最终值是传入的多个Promise决议完成的值。

   有了Promise.all方法,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加简单易懂。

    像这样的调用:

 Promise.all([request("url1"),request("url2")]).then((result)=>{
console.log(result) //[url1result,url2result]
})

    注意传入的顺序,数组promise决议的值与返回的result数组位置是一致的。对于以往的回调方式来说,这是很强大的api。

  

  Promise.race(array)

   这个方法和all调用方式一样,但是决议的方式不一样,.all等待所有决议完成新的 Promise返回决议。 而.race,一旦有某个promise决议完成,其余的会立刻终止。也就是说它只会执行最快的那个promise。

   

    ...更多api可以查看阮大大的es6教程

结束

  promise已经成为主流。我在这里只讲了一些浅见,至于更多的用法,与君共勉!

【前端】主流API-promise解析,js基础。的更多相关文章

  1. 前端面试题目汇总摘录(JS 基础篇)

    JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string typeof null; // o ...

  2. 前端工程师面试问题归纳(一、问答类html/css/js基础)

    一.参考资源 1.前端面试题及答案整理(一) 2.2017年前端面试题整理汇总100题 3.2018最新Web前端经典面试试题及答案 4.[javascript常见面试题]常见前端面试题及答案 5.W ...

  3. 从程序员到CTO的Java技术路线图 JAVA职业规划 JAVA职业发展路线图 系统后台框架图、前端工程师技能图 B2C电子商务基础系统架构解析

    http://zz563143188.iteye.com/blog/1877266在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样 ...

  4. 前端面试题目汇总摘录(JS 基础篇 —— 2018.11.02更新)

    温故而知新,保持空杯心态 JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string type ...

  5. 进击Node.js基础(二)promise

    一.Promise—Promise似乎是ES6中的规范 PROMISE的语言标准,PROMISE/A+规范,如何使用,在什么场景下使用 Promise时JS对异步操作场景提出的解决方案(回调,观察者模 ...

  6. 10慕课网《进击Node.js基础(一)》初识promise

    首先用最简单的方式实现一个动画效果 <!doctype> <html> <head> <title>Promise animation</titl ...

  7. 03慕课网《进击Node.js基础(一)》API-URL网址解析

    url url.parse(url,query,host);解析域名 url必须,地址字符串 query可选 host 可选:在不清楚协议时正确解析 querystring 字符串和对象之间互相解析 ...

  8. 前端05 /js基础

    前端05 /js基础 昨日内容回顾 css选择器的优先级 行内(1000) > id(100) > 类(10) > 标签(1) > 继承(0) 颜色 rgb(255,255,2 ...

  9. 前端-js基础

    HTML三把利剑之一,浏览器具有解析js的能力 一.js基础 在HTML中可以将JavaScript/JS的代码写在head中,被script标签所包裹,当浏览器解释HTML时,遇到style标签时, ...

  10. web前端——Vue.js基础学习

    近期项目的前端页面准备引入Vue.js,看了网上一些简介,及它和JQuery的对比,发现对于新入门的前端开发来说,Vue 其实也是比较适用的一个框架,其实用性不比JQuery差,感觉还挺有意思,于是研 ...

随机推荐

  1. Struts2第十二篇【模型驱动】

    什么是模型驱动 在Struts2中模型驱动就是用来封装数据的..完成数据的自动封装. 为什么要使用模型驱动? 我们之前就使用过Sturts2的数据自动封装功能,是用params拦截器完成的-既然有了p ...

  2. 【轉】JS,Jquery获取各种屏幕的宽度和高度

    Javascript: 网页可见区域宽: document.body.clientWidth网页可见区域高: document.body.clientHeight网页可见区域宽: document.b ...

  3. thinkphp5.0无限极分类及格式化输出

    首先我们来看数据表 从上图中可以发现,中国下有贵州,北京两个子节点,而北京有天安门一个子节点,纽约的子节点是"纽约的子类". 从pid为0看出,中国和纽约是顶级节点. 因为贵州的p ...

  4. 移动端与PHP服务端接口通信流程设计(增强版)

    增强地方一: 再增加2张表,一个接口表,一个授权表,设计参考如下: 接口表 字段名 字段类型 注释 api_id int 接口ID api_name varchar(120) 接口名,以"/ ...

  5. 微信bug:建议了解,不要实验,不要手贱,不要。。。。

    今天下午在群里聊天的时候,群友反应发现微信的一个bug:使用微信给好友发送‘15...............’(数字15后面加15个句号)会导致微信运行缓慢,到最后的应用未响应,退出微信. 解决办法 ...

  6. 执行sql时出现错误 extraneous input ';' expecting EOF near '<EOF>'

    调用jdbc执行hive sql时出现错误 Error while compiling statement: FAILED: ParseException line 5:22 extraneous i ...

  7. Linux入门(7) 脚本

    1.宣告使用的shell为何 2.注明创建者 编写作用等 3.注释每一个功能函数 执行脚本 1.修改可执行权限 chmod 755 file.sh 2.sh file.sh 可以直接运行脚本 #!/b ...

  8. 《深入浅出设计模式》读书笔记 C#版(第一章)

    原始需求和设计 事情是这样开始的,公司需要做一套程序,鸭子,设计如下: 一个鸭子父类,多个派生类,三个可override的方法. 第一次需求变更 我们要会飞的鸭子!!!!! 所以我们做了如下的更改: ...

  9. Hbase对时,时差范围的确定

    Hbase对时具有严格的要求,集群内部所有机器之间的时差默认不能超过30秒,也就是说,一旦某个regionserver节点上的时间与master节点上的时间差值超过30秒,就会导致相应的regions ...

  10. 安卓App提交应用商店时遇到的两个小问题

    陆陆续续做了一个半月左右的「喵呜天气」终于在今天下午成功提交到应用商店(腾讯应用宝).期间遇到两个小问题,记录如下: 1.上传安装包失败,提示「无法获取签名信息,请上传有效包(110506)」. 安装 ...