重学Es6 Promise
栏目: JavaScript · 发布时间: 5年前
内容简介:Promise 是异步编程的一种解决方案,比传统的回调更加合理而其人强大。Promise,简单来说,是一个容器,里面存放着某个未来才会结束的事件的结果。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 = handle client.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.constructotr return this.then( value => P.resolve(callback()).then(()=>value), reason => P.resolve(callback()).then(()=> {throw reason}) ) } 复制代码
以上所述就是小编给大家介绍的《重学Es6 Promise》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
计算机程序设计艺术(第1卷)
[美] 唐纳德·E. 克努特 / 苏运霖 / 国防工业出版社 / 2002-9 / 98.00元
7卷本《计算机程序设计艺术》的第1卷以基本的程序设计概念和技术开始,然后专注于信息结构——计算机内部信息的表示、数据元素之间的结构关系以及如何有效地处理它们,给出了对于模拟、数值方法、符号计算、软件和系统设计的初等应用。书中附有大量习题和答案,标明了难易程序及数学概念的使用。 此新版本增加了几十项简单且重要的算法和技术,并对有关数学预备知识作了大量修改以适应现时研究的趋势。一起来看看 《计算机程序设计艺术(第1卷)》 这本书的介绍吧!