前言

Promise的重要性我认为我没有必要多讲,概括起来说就是必须得掌握,而且还要掌握透彻。这篇文章的开头,主要跟大家分析一下,为什么会有Promise出现。

在实际的使用当中,有非常多的应用场景我们不能立即知道应该如何继续往下执行。最重要也是最主要的一个场景就是ajax请求。通俗来说,由于网速的不同,可能你得到返回值的时间也是不同的,这个时候我们就需要等待,结果出来了之后才知道怎么样继续下去。

// 简单的ajax原生实现
var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
var result;var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();XHR.onreadystatechange = function() {if (XHR.readyState == 4 && XHR.status == 200) {result = XHR.response;console.log(result);}
}

在ajax的原生实现中,利用了onreadystatechange事件,当该事件触发并且符合一定条件时,才能拿到我们想要的数据,之后我们才能开始处理数据。

这样做看上去并没有什么麻烦,但是如果这个时候,我们还需要做另外一个ajax请求,这个新的ajax请求的其中一个参数,得从上一个ajax请求中获取,这个时候我们就不得不如下这样做:

var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
var result;var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();XHR.onreadystatechange = function() {if (XHR.readyState == 4 && XHR.status == 200) {result = XHR.response;console.log(result);// 伪代码var url2 = 'http:xxx.yyy.com/zzz?ddd=' + result.someParams;var XHR2 = new XMLHttpRequest();XHR2.open('GET', url, true);XHR2.send();XHR2.onreadystatechange = function() {...}}
}

当出现第三个ajax(甚至更多)仍然依赖上一个请求的时候,我们的代码就变成了一场灾难。这场灾难,往往也被称为回调地狱

因此我们需要一个叫做Promise的东西,来解决这个问题。

当然,除了回调地狱之外,还有一个非常重要的需求:为了我们的代码更加具有可读性和可维护性,我们需要将数据请求与数据处理明确的区分开来。上面的写法,是完全没有区分开,当数据变得复杂时,也许我们自己都无法轻松维护自己的代码了。这也是模块化过程中,必须要掌握的一个重要技能,请一定重视。

从前面几篇文中的知识我们可以知道,当我们想要确保某代码在谁谁之后执行时,我们可以利用函数调用栈,将我们想要执行的代码放入回调函数中。

// 一个简单的封装
function want() {console.log('这是你想要执行的代码');
}function fn(want) {console.log('这里表示执行了一大堆各种代码');// 其他代码执行完毕,最后执行回调函数want && want();
}fn(want);

利用回调函数封装,是我们在初学JavaScript时常常会使用的技能。

确保我们想要的代码压后执行,除了利用函数调用栈的执行顺序之外,我们还可以利用上一篇文章所述的队列机制。

function want() {console.log('这是你想要执行的代码');
}function fn(want) {// 将想要执行的代码放入队列中,根据事件循环的机制,我们就不用非得将它放到最后面了,由你自由选择want && setTimeout(want, 0);console.log('这里表示执行了一大堆各种代码');
}fn(want);

如果浏览器已经支持了原生的Promise对象,那么我们就知道,浏览器的js引擎里已经有了Promise队列,这样就可以利用Promise将任务放在它的队列中去。

function want() {console.log('这是你想要执行的代码');
}function fn(want) {console.log('这里表示执行了一大堆各种代码');// 返回Promise对象return new Promise(function(resolve, reject) {if (typeof want == 'function') {resolve(want);} else {reject('TypeError: '+ want +'不是一个函数')}})
}fn(want).then(function(want) {want();
})fn('1234').catch(function(err) {console.log(err);
})

看上去变得更加复杂了。可是代码变得更加健壮,处理了错误输入的情况。

为了更好的往下扩展Promise的应用,这里需要先跟大家介绍一下Promsie的基础知识。

一、 Promise对象有三种状态,他们分别是:

  • pending: 等待中,或者进行中,表示还没有得到结果
  • resolved(Fulfilled): 已经完成,表示得到了我们想要的结果,可以继续往下执行
  • rejected: 也表示得到结果,但是由于结果并非我们所愿,因此拒绝执行

这三种状态不受外界影响,而且状态只能从pending改变为resolved或者rejected,并且不可逆。在Promise对象的构造函数中,将一个函数作为第一个参数。而这个函数,就是用来处理Promise的状态变化。

new Promise(function(resolve, reject) {if(true) { resolve() };if(false) { reject() };
})

上面的resolve和reject都为一个函数,他们的作用分别是将状态修改为resolved和rejected。

二、 Promise对象中的then方法,可以接收构造函数中处理的状态变化,并分别对应执行。then方法有2个参数,第一个函数接收resolved状态的执行,第二个参数接收reject状态的执行。

function fn(num) {return new Promise(function(resolve, reject) {if (typeof num == 'number') {resolve();} else {reject();}}).then(function() {console.log('参数是一个number值');}, function() {console.log('参数不是一个number值');})
}fn('hahha');
fn(1234);

then方法的执行结果也会返回一个Promise对象。因此我们可以进行then的链式执行,这也是解决回调地狱的主要方式。

function fn(num) {return new Promise(function(resolve, reject) {if (typeof num == 'number') {resolve();} else {reject();}}).then(function() {console.log('参数是一个number值');}).then(null, function() {console.log('参数不是一个number值');})
}fn('hahha');
fn(1234);

then(null, function() {}) 就等同于catch(function() {})

三、Promise中的数据传递

大家自行从下面的例子中领悟吧。

var fn = function(num) {return new Promise(function(resolve, reject) {if (typeof num == 'number') {resolve(num);} else {reject('TypeError');}})
}fn(2).then(function(num) {console.log('first: ' + num);return num + 1;
})
.then(function(num) {console.log('second: ' + num);return num + 1;
})
.then(function(num) {console.log('third: ' + num);return num + 1;
});// 输出结果
first: 2
second: 3
third: 4

OK,了解了这些基础知识之后,我们再回过头,利用Promise的知识,对最开始的ajax的例子进行一个简单的封装。看看会是什么样子。

var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';// 封装一个get请求的方法
function getJSON(url) {return new Promise(function(resolve, reject) {var XHR = new XMLHttpRequest();XHR.open('GET', url, true);XHR.send();XHR.onreadystatechange = function() {if (XHR.readyState == 4) {if (XHR.status == 200) {try {var response = JSON.parse(XHR.responseText);resolve(response);} catch (e) {reject(e);}} else {reject(new Error(XHR.statusText));}}}})
}getJSON(url).then(resp => console.log(resp));

为了健壮性,处理了很多可能出现的异常,总之,就是正确的返回结果,就resolve一下,错误的返回结果,就reject一下。并且利用上面的参数传递的方式,将正确结果或者错误信息通过他们的参数传递出来。

现在所有的库几乎都将ajax请求利用Promise进行了封装,因此我们在使用jQuery等库中的ajax请求时,都可以利用Promise来让我们的代码更加优雅和简单。这也是Promise最常用的一个场景,因此我们一定要非常非常熟悉它,这样才能在应用的时候更加灵活。

四、Promise.all

当有一个ajax请求,它的参数需要另外2个甚至更多请求都有返回结果之后才能确定,那么这个时候,就需要用到Promise.all来帮助我们应对这个场景。

Promise.all接收一个Promise对象组成的数组作为参数,当这个数组所有的Promise对象状态都变成resolved或者rejected的时候,它才会去调用then方法。

var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
var url1 = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-03-26/2017-06-10';function renderAll() {return Promise.all([getJSON(url), getJSON(url1)]);
}renderAll().then(function(value) {// 建议大家在浏览器中看看这里的value值console.log(value);
})

五、Promise.race

与Promise.all相似的是,Promise.race都是以一个Promise对象组成的数组作为参数,不同的是,只要当数组中的其中一个Promsie状态变成resolved或者rejected时,就可以调用.then方法了。而传递给then方法的值也会有所不同,大家可以再浏览器中运行下面的例子与上面的例子进行对比。

function renderRace() {return Promise.race([getJSON(url), getJSON(url1)]);
}renderRace().then(function(value) {console.log(value);
})

嗯,我所知道的,关于Promise的基础知识就这些了,如果还有别的,欢迎大家补充。

转载于:https://www.cnblogs.com/weirdoQi/p/6835734.html

前端基础进阶之Promise相关推荐

  1. boost log 能不能循环覆盖_前端基础进阶(十四):深入核心,详解事件循环机制...

    Event Loop JavaScript的学习零散而庞杂,很多时候我们学到了一些东西,但是却没办法感受到进步!甚至过了不久,就把学到的东西给忘了.为了解决自己的这个困扰,在学习的过程中,我一直在试图 ...

  2. jquery function_前端基础进阶(十三)详细图解jQuery扩展jQuery插件

    UI 鉴赏 早几年学习前端,大家都非常热衷于研究jQuery源码. 我至今还记得当初从jQuery源码中学到一星半点应用技巧的时候常会有一种发自内心的惊叹,"原来JavaScript居然可以 ...

  3. 前端基础进阶(七):函数与函数式编程

    纵观JavaScript中所有必须需要掌握的重点知识中,函数是我们在初学的时候最容易忽视的一个知识点.在学习的过程中,可能会有很多人.很多文章告诉你面向对象很重要,原型很重要,可是却很少有人告诉你,面 ...

  4. 前端基础进阶(十):面向对象实战之封装拖拽对象

    https://segmentfault.com/a/1190000012646488  https://yangbo5207.github.io/wutongluo/ 说明:此处只是记录阅读前端基础 ...

  5. 前端基础进阶(十三):透彻掌握Promise的使用,读这篇就够了

    Promise的重要性我认为我没有必要多讲,概括起来说就是必须得掌握,而且还要掌握透彻.这篇文章的开头,主要跟大家分析一下,为什么会有Promise出现. 在实际的使用当中,有非常多的应用场景我们不能 ...

  6. 前端基础进阶(二):执行上下文详细图解

    我们在JS学习初期或者面试的时候常常会遇到考核变量提升的思考题.比如先来一个简单一点的. console.log(a); // 这里会打印出什么? var a = 20; 暂时先不管这个例子,我们先引 ...

  7. 【前端基础进阶】JS-Object 功能详解

    Object.assign(target,source1,source2,...) 该方法主要用于对象的合并,将源对象source的所有可枚举属性合并到目标对象target上,此方法只拷贝源对象的自身 ...

  8. 前端工程师就业班Sass基础+进阶+案例开发经验【JS++前端】-艾小野-专题视频课程...

    前端工程师就业班Sass基础+进阶+案例开发经验[JS++前端]-98人已学习 课程介绍         本套课程是摘选自JS++第三期前端工程师精英就业班系列课程,进行系统深度的对Sass技术知识点 ...

  9. JavaScript 内存机制(前端同学进阶必备)

    JavaScript 内存机制(前端同学进阶必备) 简介 每种编程语言都有它的内存管理机制,比如简单的C有低级的内存管理基元,像malloc(),free().同样我们在学习JavaScript的时候 ...

最新文章

  1. 【正则表达式】值匹配汉字的正字表达式
  2. linuxsvn源代码版本库建立
  3. 操作选项_消防设施操作员关键技能之六:能切换集中火灾报警控制器、消防联动控制器工作状态...
  4. Android手机rom分区以及sd卡总结
  5. Anaconda:Anaconda安装图文教程及其tensorflow安装、运行、测试之最强详细攻略
  6. 分布式文件服务器FastDFS
  7. Define change document object
  8. 【mysql】DATE_FORMAT()日期格式化
  9. 当下流行的分布式文件系统大阅兵
  10. C/C++ 中判断某一文件或目录是否存在
  11. matlab分析机翼,基于Matlab对机翼断面下轮廓线的数值分析
  12. Python组合列表中多个整数得到最小整数(一个算法的巧妙实现)
  13. Android集成Zxing
  14. smartadmin官网_smartadmin api_smartadmin 下载
  15. 回文数字 观察数字:12321,123321都有一个共同的特征,无论从左到右读还是从右向左读;都是相同的。这样的数字叫做: 回文数字。 本题要求你找到一些5位或6位的十进制数字。满足要求: 该数字
  16. php无版权图库api,12个无版权限制的大图特供网站_交互设计教程
  17. 当div的宽度为百分比时,如何设置成为一个正方形?
  18. openlayers 地图上加图标_OpenLayers学习笔记中级篇(四、地图图标操作)
  19. 实业优则投资:危险的游戏
  20. Ubuntu中shell命令-(4)-echo/tar/which/whereis/ps/kill/top/df/du

热门文章

  1. python getopt_python 之 分割参数getopt
  2. 木质机器人挂坠_木质挂坠相比绚烂夺目的金银首饰,用木头做的饰品更显得古香古色...
  3. 计算机课评课用语,【数学评课50条】_评课常用语50条
  4. 计算机二级office试题27答案,2017年12月计算机二级MS Office习题答案(一)
  5. c+mysql主从切换_mysql主从配置
  6. keras-yolov3 + Kalman-Filter 进行人体多目标追踪(含代码)
  7. caffe+GAN︱PPGN生成模型5则官方案例(caffe版)
  8. 词嵌入word2vec、字词嵌入fastText、全局词嵌入Glove直接的联系与关系
  9. 骚年,还在为歌荒发愁吗?python教你爬取网易云热门歌单
  10. inotify实时同步工具理论和实战