前端知识点回顾之重点篇——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 块级格式化上下文是页面中的一块渲染区域, ...
随机推荐
- 【Java并发】线程安全和内存模型
一.概述 1.1 什么是线程安全? 1.2 案例 1.3 线程安全解决办法: 二.synchronized 2.1 概述 2.2 同步代码块 2.3 同步方法 2.4 静态同步函数 2.5 总结 三. ...
- mybatis-generator-gui
mybatis-generator-gui介绍 mybatis-generator-gui是基于mybatis generator开发一款界面工具, 本工具可以使你非常容易及快速生成Mybatis的J ...
- Tarjan-CV/BCC/SCC算法学习笔记
DFS性质的应用--利用Tarjan算法求割顶.BCC.SCC 整理自<算法竞赛入门经典--训练指南>以及网络 DFS (depth first search)深度优先搜索算法 dfs森林 ...
- Python&Selenium 数据驱动【unittest+ddt+json+HTMLTestRunner】
一.摘要 本博文将介绍Python和Selenium做自动化测试的时候,基于unittest框架,借助ddt模块使用json文件作为数据文件作为测试输入,最后借助著名的HTMLTestRunner.p ...
- javascript代码模块化解决方案
我们用模块化的思想进行网页的编写是为了更好的管理我们的项目,模块与模块之间是独立存在的,每个模块可以独立的完成一个子功能. 一.服务器和桌面环境中的Javascript代码模块化:CommonJS M ...
- Permission denied (publickey,gssapi-keyex,gssapi-with-mic)
当出现警告的时候,恭喜你,你已经离成功很近了. 远程主机这里设为slave2,用户为Hadoop. 本地主机设为slave1 以下都是在远程主机slave2上的配置,使得slave1可以免密码连接到s ...
- TBDR下msaa 在metal vulkan和ogles的解决方案
https://developer.arm.com/solutions/graphics/developer-guides/understanding-render-passes/multi-samp ...
- thinkphp5.1整合swoole
该方法仅作一种思路参考,实际应用也许会破坏thinkphp5.1的路由功能,并带来诸多问题,请读者尽量按照tp5.1官方的技术整合手段进行,按照tp5.1官方用户手册的方法可以实现swoole 风格的 ...
- springboot2.0入门(四)----mock模拟测试+单元测试
一.本节主要记录模拟测试.单元测试: 二.mock 测试 1.1什么是Mock? 在面向对象程序设计中,模拟对象(英语:mock object,也译作模仿对象)是以可控的方式模拟真实对象行为的假的对象 ...
- 中介者模式(Mediator)---行为型
1 基础知识 定义:用一个中介对象来封装一系列的对象交互.中介者使得各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 本质:封装交互 使用场景:(1)如果一组对象之间的 ...