重学Es6 Promise
Promise 含义
Promise 是异步编程的一种解决方案,比传统的回调更加合理而其人强大。
Promise,简单来说,是一个容器,里面存放着某个未来才会结束的事件的结果。Promise是一个对象,用来获取异步操作的消息。
Promise有以下两个特点:
1 对象状态不受外界影响。
有三种状态:Pending(进行中),Fulfilled(已成功),Rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何操作都无法改变这个状态。
2 一旦改变,不会再变,任何时候都可以得到这个结果。
Promise对象的状态改变只有两种可能:从Pending 到 Fulfilled 或者 从Pending 到 Rejected。只要这两种情况发生,状态就会凝固,不会再变,一直保持这个结果。这时就称为 Resolved(已定型)。就算改变已经发生,再对Promise添加回调函数,也会得到这个结果。 这与事件(event)完全不同,事件的特点就是:如果错过了,再去监听是得不到结果的。
Promise 缺点:
1 无法取消。一旦建立就会立即执行,无法中途取消。
2 如果不设置回调函数,Promise内部报错不会抛出到外面。
3 当处于Pending状态,无法得知目前进展到哪一阶段(是刚刚开始,还是即将完成?)
基本用法
var promise = new Promise((resolve,reject) => {// ...if(/* .....*/) {resolve(value)} else {reject(error)}
})
复制代码
resolve作用是将Promise状态由 未完成编程成功,在异步操作成功时调用,并将异步操作结果作为参数传播出去。
reject函数作用是,将Promise状态从未完成变为失败,在异步操作失败时调用,并将异步操作失败报出的错误传递出去。
Promise 实例生成后,可以调用then,指定 resolved 和 rejected 状态的回调函数。
promise.then(function(val){// success
}, function(error) {// failure
})
复制代码
then方法接受两个回调函数作为参数。第一个是 Promise 对象的状态变为Resolved时调用,第二个回调是Promise变为Rejected时调用。第二个函数时可选的。
function timeout(ms){return new Promise((resolve,reject) => {setTimeout(resolve,ms,'done')})
}
timeout(100).then((value) => {console.log(value)
})
复制代码
Promise 新建好之后就会立即执行。
let promise = new Promise(function(resolve,reject) {console.log('Promise');resolve();
})promise.then(function(){console.log('Resolved')
})console.log('Hi')
// Promise
// Hi
// Resolves
复制代码
异步加载图片:
function loadImgAsync(url) {return new Promise(function(resolve,reject) {var img = new Image()img.onload = function(){resolve(img)}img.onerror = function(){reject(new Error('Could not load img at ' + url))}img.src = url})
}
复制代码
promise 实现 AJAX
var getJSON = function (url) {var promise = new Promise((resolve,reject)=> {var client = new XMLHttpRequest()client.open('GET',url)client.onreadystatechange = handleclient.responseType = 'json'client.setRequestHeader("Accept","application/json")client.send()function handler(){if(this.readyState!==4){return }if(this.status == 200){resolve(this.response)} else {reject(new Error(this.statusText))}}})return promise;
}getJSON("/post.json").then((json)=>{console.log('Contents ' + json)
}, function(error){console.log(error)
})
复制代码
var p1 = new Promise(function (resolve,reject){setTimeout(()=>{reject(new Error('fail'),3000)})
})var p2 = new Promise(function(resolve,reject){setTimeout(()=>{resolve(p1)},1000)
})p2
.then(rsult => console.log(result))
.catch(error => console.log(error))
// Error: fail
复制代码
一般来说,调用resolve 或者 reject 以后,Promise的使命就已经完成了,后面的操作应该放到 then ,而不应该直接写到 resolve 或者 reject 后面,所以最好在它们之前 添加 return 语句,这样就不会产生意外。
new Promise((resolve,reject) => {return resolve(1);// 后面不会执行console.log(2)
})
复制代码
Promise.prototype.then()
Promise实例具有 then 方法,作用是 为 Promise 实例添加状态改变时的回调函数。
then 方法 返回一个新的 Promise 实例(不是原来那个Promise),因此 可以使用 链式写法,then 后面 再 添加 另外一个 then。
getJSON("/posts.json").then(function(json){return json.post
}).then(function(post){// ...
})
复制代码
链式调用的 then 可以指定 一组按照次序调用的回调函数。 前一个回调函数可能返回的还是一个Promise,后一个回调函数就会等待该Promise 对象的状态发生变化,在被调用。
getJSON("/post/1.json").then(function(post){return getJSON(post.commentUrl)
}).then(function funcA(comments) {console.log("resolved")
},function funcB(error){console.log(error)
})
复制代码
Promise.prototype.catch()
这个方法 是 .then(null, rejection) 的别名,指定发生错误时的回调。
getJSON('/posts.json').then(function(posts){// ...
}).catch(function(error){console.log("error " + error )
})
复制代码
Promise 在 resolve 语句之后 抛出错误,并不会被捕获,等于没有抛出。因为Promise状态一旦发生改变,就会永久保存这个状态,不会改变了。
Promise 对象错误具有“冒泡”性质,会一直向后传递,直到捕获到为止,错误总会被下一个catch捕获
一般不要在 then 方法中定义 Rejected 状态的回调函数,而应总是使用catch方法。
var someAsyncThing = function(){return new Promise((resolve,reject)=>{// 报错 x 未声明resolve(x + 2)})
}
someAsyncThing().then(()=>{return someotherAsyncThing()
}).catch(error => {console.log('oh no' , error)// 报错 y 没有声明y + 2
}).then(()=>{console.log('carry on')
})
// oh no [ReferenceError: x is not defined ]
复制代码
catch方法抛出一个错误,后面如果没有catch,导致这个错误不会被捕获,也不会传递到外层。
可以用 第二个 catch 方法捕获 前一个catch 方法抛出的错误。
someAsyncThing().then(()=>{return someotherAsyncThing()
}).catch(error => {console.log('oh no' , error)// 报错 y 没有声明y + 2
}).catch(error=>{console.log('carry on ', error)
})
复制代码
Promise.all()
将多个 Promise 实例 包装成一个新的 Promise实例。
var p = Promise.all([p1, p2, p3])
p 状态 由 p1,p2,p3 决定,分两种情况。
1 只有p1,p2,p3 状态都变成 fulfilled ,p 的状态 才会变成 fulfilled,此时 p1,p2,p3 返回值组成一个数组,传递给 p 的回调。
2 只要 p1,p2,p3 有一个被Rejected,p 状态也会变成 Rejected,此时,第一个被 Rejected 的实例返回值会传递给p的回调函数。
var promises = [2,3,5,7,11,13].map(function(id) {return getJSON('/post/'+id+'.json')
})promise.all(promises).then(posts=>{//...
}).catch(reason=>{//...
})
复制代码
另一个例子
const databasePromise = connectDatabase()
const bookPromise = databasePromise.then(findAllBooks)
const userPromise = databasePromise.then(getCurrentUser)
Promise
.all([bookPromise,userPromise])
.then(([books,user])=>{//...
})
复制代码
如果作为参数的Promise自身定义了catch方法,那么被rejected大时并不会触发 Promise.all 的 catch 方法
Promise.race()
var p = new Promise.race([p1,p2,p3])
复制代码
只要 p1,p2,p3中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise 实例 返回值就是传递给p 的回调函数。
const p = Promise.race([fetch('/xxx'),new Promise((resolve,reject)=>{setTimeout(()=>{reject(new Error('time out'))},5000)})
])
p.then(res=>{console.log(res)
})
.catch(error => {console.log(error)
})
复制代码
附加方法
done()
无论Promise对象的回调链以then方法还是catch结尾,最后一个方法抛出的错误都可能无法捕捉到(Promise内部的错误不会冒泡的全局)因此,提供一个 done 方法,总是处于回调链尾端,保证抛出任何可能的错误。
asyncFunc()
.then()
.catch()
.then()
.done()
复制代码
实现
Promise.prototype.done = function(onFulilled, onRejected){this.then(onFulilled, onRejected).catch(function(resason){setTimeout(() => {throw reason},0)})
}
复制代码
finally()
finally方法用于指定不管Promise对象最后状态如何都会执行的操作。与 done 最大的区别在于 他接受一个不普通的回调函数作为参数,该函数不管怎样都必须执行。
实现
Promise.prototype.finally = function(callback){let P = this.constructotrreturn this.then(value => P.resolve(callback()).then(()=>value),reason => P.resolve(callback()).then(()=> {throw reason}))
}
复制代码
转载于:https://juejin.im/post/5cf703a6518825662421fc1c
重学Es6 Promise相关推荐
- 重学ES6 函数的扩展(下)
尾调用优化 什么是尾调用 尾调用(Tail Call)是函数式变成的重要概念,本身很简单,就是指函数的最后一步,调用另一个函数. function f(x){return g(x) } // 函数最后 ...
- 重学ES6 模板字符串
在两三年前,jQuery还是比较主流的开发技术,当我们要为页面添加DOM时,一般,我们是这样写的 $("#container").append('Today is <b> ...
- winter重学前端——训练营预习课
重学前端读书笔记 javascript javascript 类型 javascript对象 面向对象与基于对象 模拟类 JavaScript 中的对象分类 javascript 执行 Promise ...
- 【图文并茂,点赞收藏哦!】重学巩固你的Vuejs知识体系
前沿 置身世外只为暗中观察!!!Hello大家好,我是魔王哪吒!重学巩固你的Vuejs知识体系,如果有哪些知识点遗漏,还望在评论中说明,让我可以及时更新本篇内容知识体系.欢迎点赞收藏! 谈谈你对MVC ...
- 重学巩固你的Vuejs知识体系(上)
前沿 置身世外只为暗中观察!!!Hello大家好,我是魔王哪吒!重学巩固你的Vuejs知识体系,如果有哪些知识点遗漏,还望在评论中说明,让我可以及时更新本篇内容知识体系.欢迎点赞收藏! 谈谈你对MVC ...
- 判断字符串 正则_(重学前端 - JavaScript(模块一)) 14、引用类型之 RegExp (正则)(详述)...
上一篇文章介绍了 JavaScript 中的 Date 类型,从地理方面的原理知识开始入手,如果大家认真看过上一篇文章,相信 JavaScript 中的 Date 类型已经难不住大家了!!! 但是今天 ...
- 重学前端学习笔记(八)--JavaScript中的原型和类
笔记说明 重学前端是程劭非(winter)[前手机淘宝前端负责人]在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入winter的专 ...
- vue process.env获取不到_从文档开始,重学vue(下)源码级别
此篇文章主要是从应用及源码层面讲解vue部分常用api,阅读起来可能略有难度,新手可以看<从文档开始,重学vue(上)> 示例代码均在vue-cli3中完成 Vue.extend() 可以 ...
- css html 双面打印_CSS语法与规则 — 重学CSS
我是三钻,一个在<技术银河>中等你们一起来终生漂泊学习. 点赞是力量,关注是认可,评论是关爱!下期再见 ! 前言 进入重学 CSS 的第一步,首先需要找到一些线索.我们在前面的课程中讲学习 ...
- 重学JavaScript系列之一_引用类型
重学JavaScript系列之一_引用类型 ECMAScript中,引用数据是一种数据结构,用于将数据和功能组织在一起,有时候被称为类 ES6中使用Class定义一个类 引用类型的值(对象)是引用类型 ...
最新文章
- 基于深度卷积神经网络的循环优化操作和FPGA加速中的数据流
- 使用nmap-converter将nmap扫描结果XML转化为XLS实战
- 帝国 php 7.0 默认 后台用户名及认证码,帝国CMS后台管理员帐号密码、认证码、安全答案忘记了怎么办?...
- 加分二叉树 java_P1040 加分二叉树
- c++软件开发面试旋极面试题_腾讯软件开发面试题(有详细解答)
- [译]GLUT教程 - 笔划字体
- visualstudio学习
- Ubuntu10.04设备未托管
- 读取JSON文件并 排序,分组,
- 在线制作车牌效果图_厦门车牌识别系统生产厂家直销
- 天津东软实训第八天------倒排索引
- 机器人跟踪_使用手机和机器学习跟踪睡眠
- 网络安全工程师与渗透测试工程师有哪些区别
- ArcGIS空间统计——点密度计算
- 不知道RabbitMQ中Exchange类型Internal是什么意思?这边来~
- 《自控力》 第一章读书笔记
- select下拉列表支持搜索功能
- 计算机不能通讯,S7-200与电脑不能通讯问题
- fuchsia Zircon Hypervisor:调测手段
- 信号时频域分析 ——EMD/BEMD/LMD 算法原理
热门文章
- SPSS 虚拟变量(图文+数据集)【SPSS 038期】
- mysql出现死锁场景_mysql死锁场景分析
- java 反射 框架_Java——利用反射实现框架类
- yolo-v5连接手机摄像头实时检测的步骤
- python工厂方法_Python设计模式:工厂方法模式初探
- 同花顺开放接口api_接口大师,即刻构建你的OpenAPI+开放平台
- 经典傅里叶算法小集合 附完整c代码
- vi 打开文件,行末尾有^M
- python进程之间修改数据[Manager]与进程池[Pool]
- android view