前端知识点回顾之重点篇——ES6的Promise对象
Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
Promise对象代表一个异步操作,有三种状态:
pending(进行中)、fulfilled(已成功)和rejected(已失败)。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
回顾ES5中若要实现以下异步编程逻辑,将会形成回调地狱(回调不断嵌套回调)
setTimeout(() => {
console.log("事件A");
setTimeout(() => {
console.log("事件B");
setTimeout(() => {
console.log("事件C");
}, Math.random()*1000);
}, Math.random()*1000);
}, Math.random()*1000);
ES6中使用Promise:
let p = new Promise((resolve,reject)=>{
//一些异步操作
settimeout(()=>{
console.log("123")
resolve("abc");
},0)
})
.then(function(data){
//resolve状态
console.log(data)
},function(err){
//reject状态
console.log(err)
})
//'123'
//'abc'
Promise对象接受一个函数,其两个参数分别表示resolve状态和reject状态,函数中执行的异步操作结果可以通过调用形参名字的方法来分别表示resolve状态和reject状态并将异步结果进行传参,resolve()和reject()的参数会传递到.then中相应状态的回调函数的形参中。
以下来源:https://www.cnblogs.com/sweeeper/p/8442613.html
then()方法
简单来讲,then 方法就是把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。
而 Promise 的优势就在于这个链式调用。我们可以在 then 方法中继续写 Promise 对象并返回,然后继续调用 then 来进行回调操作。
//做饭
function cook(){
console.log('开始做饭。');
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('做饭完毕!');
resolve('鸡蛋炒饭');
}, 1000);
});
return p;
}
//吃饭
function eat(data){
console.log('开始吃饭:' + data);
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('吃饭完毕!');
resolve('一块碗和一双筷子');
}, 2000);
});
return p;
}
function wash(data){
console.log('开始洗碗:' + data);
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('洗碗完毕!');
resolve('干净的碗筷');
}, 2000);
});
return p;
}
使用then链式调用这三个方法:
cook()
.then(function(data){
return eat(data);
})
.then(function(data){
return wash(data);
})
.then(function(data){
console.log(data);
});
可以化简成:
cook()
.then(eat)
.then(wash)
.then(function(data){
console.log(data);
});
运行结果如下:
开始做饭。
做饭完毕!
开始吃饭:鸡蛋炒饭
吃饭完毕!
开始洗碗:一块碗和一双筷子
洗碗完毕;
干净的碗筷
在then方法中,可以直接return数据而不是Promise对象,在后面的then中也能接收到数据。或者更可取的方法是使用Promise.resolve()方法return一个promise对象以便后续可以继续使用then方法。
reject()方法
上面样例我们通过 resolve 方法把 Promise 的状态置为完成态(Resolved),这时 then 方法就能捕捉到变化,并执行“成功”情况的回调。
而 reject 方法就是把 Promise 的状态置为已失败(Rejected),这时 then 方法执行“失败”情况的回调(then 方法的第二参数)。
//做饭
function cook(){
console.log('开始做饭。');
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('做饭失败!');
reject('烧焦的米饭');
}, 1000);
});
return p;
}
//吃饭
function eat(data){
console.log('开始吃饭:' + data);
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('吃饭完毕!');
resolve('一块碗和一双筷子');
}, 2000);
});
return p;
}
cook()
.then(eat, function(data){
console.log(data + '没法吃!');
})
运行结果:
开始做饭。
做饭失败!
烧焦的米饭没法吃!
catch()方法
它可以和 then 的第二个参数一样,用来指定 reject 的回调
cook()
.then(eat)
.catch(function(data){
console.log(data + '没法吃!');
});
它的另一个作用是,当执行 resolve 的回调(也就是上面 then 中的第一个参数)时,如果抛出异常了(代码出错了),那么也不会报错卡死 js,而是会进到这个 catch 方法中。
//做饭
function cook(){
console.log('开始做饭。');
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('做饭完毕!');
resolve('鸡蛋炒饭');
}, 1000);
});
return p;
} //吃饭
function eat(data){
console.log('开始吃饭:' + data);
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('吃饭完毕!');
resolve('一块碗和一双筷子');
}, 2000);
});
return p;
} cook()
.then(function(data){
throw new Error('米饭被打翻了!');
eat(data);
})
.catch(function(data){
console.log(data);
}); //执行结果
开始做饭。
做饭完毕!
Error:米饭被打翻了!
Promise.all()方法
Promise 的 all 方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。
它的状态由参数中的各个promise对象决定,分成两种情况。
只有所有参数的Promise的状态都变成fulfilled,它的状态才会变成fulfilled。 此时每一个Promise的返回值组成一个数组,传递给它的回调函数。
只要有一个被rejected,它的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给它的回调函数。
//切菜
function cutUp(){
console.log('开始切菜。');
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('切菜完毕!');
resolve('切好的菜');
}, 1000);
});
return p;
}
//烧水
function boil(){
console.log('开始烧水。');
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('烧水完毕!');
resolve('烧好的水');
}, 1000);
});
return p;
}
Promise
.all([cutUp(), boil()])
.then(function(results){
console.log("准备工作完毕:");
console.log(results);
});
//执行结果
开始切菜。
开始烧水。
切菜完毕!
烧水完毕!
准备工作完毕:
["切好的菜", "烧好的水"]
Promise.race()方法
race 按字面解释,就是赛跑的意思。race 的用法与 all 一样,只不过 all 是等所有异步操作都执行完毕后才执行 then 回调。而 race 的话只要有一个异步操作执行完毕,就立刻执行 then 回调。
注意:其它没有执行完毕的异步操作仍然会继续执行,而不是停止。
这里我们将上面样例的 all 改成 race
Promise
.race([cutUp(), boil()])
.then(function(results){
console.log("准备工作完毕:");
console.log(results);
});
//执行结果
开始切菜。
开始烧水。
切菜完毕!
准备工作完毕:
切好的菜
烧水完毕!
race 使用场景很多。比如我们可以用 race 给某个异步请求设置超时时间,并且在超时后执行相应的操作。
//请求某个图片资源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}
//延时函数,用于给请求计时
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('图片请求超时');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});
上面代码 requestImg 函数异步请求一张图片,timeout 函数是一个延时 5 秒的异步操作。我们将它们一起放在 race 中赛跑。
- 如果 5 秒内图片请求成功那么便进入 then 方法,执行正常的流程。
- 如果 5 秒钟图片还未成功返回,那么则进入 catch,报“图片请求超时”的信息。
Promise.resolve()方法
将现有对象转为 Promise 对象。
Promise.resolve('123')
// 等价于
new Promise(resolve => resolve('123'))
根据参数不同分成四种情况:
参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
参数是一个thenable对象
thenable对象指的是具有then方法的对象,比如下面这个对象。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
}; let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
参数不是具有then方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。
const p = Promise.resolve('Hello'); p.then(function (s){
console.log(s)
});
// Hello
不带有任何参数
Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
需要注意的是,立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。
setTimeout(function () {
console.log('three');
}, 0); Promise.resolve().then(function () {
console.log('two');
}); console.log('one'); // one
// two
// three
上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。
Promise.reject()方法
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
注意,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。
前端知识点回顾之重点篇——ES6的Promise对象的更多相关文章
- 前端知识点回顾之重点篇——ES6的async函数和module
async函数 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是 Generator 函数的语法糖 什么是语法糖? 意指那些没有给计算机语言添加新功能,而只是 ...
- 前端知识点回顾之重点篇——ES6的Iterator和Generator
Iterator 迭代器是一种接口.是一种机制. 为各种不同的数据结构提供统一的访问机制.任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员). Iter ...
- 前端知识点回顾之重点篇——CSS中vertical align属性
来源:https://www.cnblogs.com/shuiyi/p/5597187.html 行框的概念 红色(line-height)为行框的顶部和底部,绿色(font-size)为字体的高度, ...
- 前端知识点回顾之重点篇——CSS中flex布局
flex布局 来源: http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool 采用 Flex 布局的元素 ...
- 前端知识点回顾之重点篇——jQuery实现的原理
jQuery jQuery的实现原理 参考:https://blog.csdn.net/zhouziyu2011/article/details/70256659 外层沙箱和命名空间$ 为了避免声明了 ...
- 前端知识点回顾之重点篇——CORS
CORS(cross origin resource sharing)跨域资源共享 来源:http://www.ruanyifeng.com/blog/2016/04/cors.html 它允许浏览器 ...
- 前端知识点回顾之重点篇——AJAX
Ajax(Asynchronous JavaScript and XML) 这种技术就是无须刷新页面即可从服务器中取得数据,但不一定是XML数据.在原生方法上,Ajax技术的核心是XMLHttpReq ...
- 前端知识点回顾之重点篇——JavaScript异步机制
JavaScript异步机制 来源:https://www.cnblogs.com/zhaodongyu/p/3922961.html JavaScript是单线程异步执行的,单线程意味着代码在任务队 ...
- 前端知识点回顾之重点篇——CSS中的BFC
BFC布局(Block Formatting Contexts) 来源:https://www.cnblogs.com/lzbk/p/6057097.html 块级格式化上下文是页面中的一块渲染区域, ...
随机推荐
- windows 日志清理和设置
Windows日志路径 c:/windows/system32/winevt/logs 这里的日志文件可以ctrl+a 选中后使用shift+delete进行删除,删不掉的可以点击跳过. 在“管理 ...
- 将windows当做linux/Mac来用 scoop强大的包管理工具
在Linux中有apt-get.yum这些包安装管理 安装相当方便:如ubuntu安装一个mysql5.7,只需要一个简单的命令: apt-get 而在windows中需要在MySQL官网下载对应版本 ...
- 关于linux一些备份、还原,压缩,归档的命令
15.1 gzipgzip(1) 是GNU的压缩程序.它只对单个文件进行压缩.基本用法如下:$ gzip filename程序执行以后,文件名会变成filename.gz,而且一般情况下大小会比原文件 ...
- python基础:if判断与流程控制案例
# 1.使用while循环输出1 2 3 4 5 6 8 9 10 count = 0 while count < 11: if count == 7: count += 1 continue ...
- Hadoop_13_Hadoop Shell脚本采集日志上传到HDFS
案例1:开发shell采集脚本 1.点击流日志每天都10T,在业务应用服务器上,需要准实时上传至数据仓库(Hadoop HDFS)上 2.一般上传文件都是在凌晨24点操作,由于很多种类的业务数据都要在 ...
- 作业九——DFA最小化
1.将DFA最小化:教材P65 第9题 I {1, 2, 3, 4, 5} {6, 7} {1, 2}b->{1, 2, 3, 4, 5} {3, 4}b->{6, 7} {5}b-> ...
- jemeter正则
关联 jmeter关联用正则表达式 引用名称:随便取 正则表达式: 模板:$1$(这是固定的) 匹配数字:1 缺省值:默认不成功传的值 正则表达式在相应数据里面找 把变 ...
- C#实现10进制转2进制
这几天在复习计算机原理,看到二进制忽然想到二进制转10进制的公式,然后转念一想10进制转二进制的公式好像没印象,那索性自己写出来. 结果学渣的我发现,并不能写出来!什么数列,对数,xx函数忘得一干二净 ...
- C#的队列(Queue,ConcurrentQueue)和堆栈(Stack,ConcurrentStack)
一.Queue 表示对象的先进先出(FIFO)集合,非线程安全 常用方法 Dequeue 入队 Enqueue 出队 Contains 队列中是否存在某元素 Clear 清空队列 封装: /// ...
- 二叉堆的介绍和Java实现
一.堆和二叉堆 堆,英文名称Heap,所谓二叉堆(也有直接称二叉堆为堆的),本质上是一个完全二叉树,前面也提到过,如果树接近于完全二叉树或者满二叉树,采用顺序存储代价会小一点,因此常见的二叉堆均是顺序 ...