【前端】主流API-promise解析,js基础。
前言
在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。
结束
promise已经成为主流。我在这里只讲了一些浅见,至于更多的用法,与君共勉!
【前端】主流API-promise解析,js基础。的更多相关文章
- 前端面试题目汇总摘录(JS 基础篇)
JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string typeof null; // o ...
- 前端工程师面试问题归纳(一、问答类html/css/js基础)
一.参考资源 1.前端面试题及答案整理(一) 2.2017年前端面试题整理汇总100题 3.2018最新Web前端经典面试试题及答案 4.[javascript常见面试题]常见前端面试题及答案 5.W ...
- 从程序员到CTO的Java技术路线图 JAVA职业规划 JAVA职业发展路线图 系统后台框架图、前端工程师技能图 B2C电子商务基础系统架构解析
http://zz563143188.iteye.com/blog/1877266在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样 ...
- 前端面试题目汇总摘录(JS 基础篇 —— 2018.11.02更新)
温故而知新,保持空杯心态 JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string type ...
- 进击Node.js基础(二)promise
一.Promise—Promise似乎是ES6中的规范 PROMISE的语言标准,PROMISE/A+规范,如何使用,在什么场景下使用 Promise时JS对异步操作场景提出的解决方案(回调,观察者模 ...
- 10慕课网《进击Node.js基础(一)》初识promise
首先用最简单的方式实现一个动画效果 <!doctype> <html> <head> <title>Promise animation</titl ...
- 03慕课网《进击Node.js基础(一)》API-URL网址解析
url url.parse(url,query,host);解析域名 url必须,地址字符串 query可选 host 可选:在不清楚协议时正确解析 querystring 字符串和对象之间互相解析 ...
- 前端05 /js基础
前端05 /js基础 昨日内容回顾 css选择器的优先级 行内(1000) > id(100) > 类(10) > 标签(1) > 继承(0) 颜色 rgb(255,255,2 ...
- 前端-js基础
HTML三把利剑之一,浏览器具有解析js的能力 一.js基础 在HTML中可以将JavaScript/JS的代码写在head中,被script标签所包裹,当浏览器解释HTML时,遇到style标签时, ...
- web前端——Vue.js基础学习
近期项目的前端页面准备引入Vue.js,看了网上一些简介,及它和JQuery的对比,发现对于新入门的前端开发来说,Vue 其实也是比较适用的一个框架,其实用性不比JQuery差,感觉还挺有意思,于是研 ...
随机推荐
- 才趟过的一个坑,css造成的Validform表单提交按钮点击无效
最近入手的一个项目,在开发的过程中,遇到了一个以前没遇到过的问题,废了半天的功夫才弄懂原因,留下足迹,警醒后人,下面开始讲故事啦! 在一个昏天暗地的上午,我一个人照常坐在办公室安静的工作中!项目编码已 ...
- java 数组内的最大组合数
给定一个任意长度的java数组,求数组内的数能组合出来的最大整数比如说{9,98,123,32} 最大就是 99832123 import java.util.Arrays; import java. ...
- MyBatis学习(一)简介及入门案例
1.什么是MyBatis? MyBatis是一个支持普通SQL查询,存储过程,和高级映射的优秀持久层框架.MyBatis去掉了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBati ...
- 14.LINUX-platform机制实现驱动层分离(详解)
版权声明:本文为博主原创文章,未经博主允许不得转载. 本节目标: 学习platform机制,如何实现驱动层分离 1.先来看看我们之前分析输入子系统的分层概念,如下图所示: 如上图所示,分 ...
- 理解及操作环境变量(基于Mac操作)
通过本文,简单的了解下环境变量及其操作,与便于遇到相关问题时能够准确快捷的解决. 什么是环境变量 An environment variable is a dynamic-named value th ...
- 当你的SSM项目中的springmvc.xml发生第一行错误解决方案
当你新建了一个SSM项目,你复制网上的xml文件来配置或者你下载了一个SSM项目打开发现xml文件错误,打开是第一行报错的时候你是不是很懵逼 或者是这样 总之就是xml文件中<?xml vers ...
- Hive基础(1)---Hive是什么
1. Hive是什么 Hive是基于Hadoop的数据仓库解决方案.由于Hadoop本身在数据存储和计算方面有很好的可扩展性和高容错性,因此使用Hive构建的数据仓库也秉承了这些特性. 这是来自官方的 ...
- Life Forms (poj3294 后缀数组求 不小于k个字符串中的最长子串)
(累了,这题做了很久!) Life Forms Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 8683 Accepted ...
- 为什么说程序员都应该玩一玩GitHub
既熟悉又陌生的GitHub 关于GitHub,相信每一个程序员都再熟悉不过了.它为开发者提供Git仓库的托管服务,是全世界最大的代码集中地,被戏称为“全球最大同性交友网站”. 但是对于很大一部分程序员 ...
- Jmeter的安装和启动时出现unable to access jarfile apachejmeter.jar error value=1错误处理
Jmeter是纯Java开发的, 能够运行Java程序的系统一般都可以运行Jmeter, 如:Windows. Linux. mac等. 由于是由Java开发,所以自然需要jdk环境. Windows ...