14章 promise对象

本文深入探讨Promise的工作原理,包括错误处理、链式调用、Promise.all及Promise.race等高级特性,帮助读者掌握异步编程的最佳实践。

1:
下面的例子,promise指定在下一轮‘事件循环’再抛出错误;到了那个的时候,promise的运行已经结束,所以这个错误实在promise函数体外抛出来的;会冒泡到最外层;成为了没有捕获的错误;

var promise=new Promise(function (resolve,reject) {
    resolve('OK')
    setTimeout(function () {
        throw new Error('TEST1')
    },0)
    setTimeout(function () {
        throw new Error('TEST12')
    },2000)
})
promise.then(function (value) {
    console.log(value)
})

运行结果如下:
webstrom环境错误如下:
这里写图片描述
google环境下的错误如下
这里写图片描述
2:
node的unhandledRejection事件;专门监听没有捕获的reject错误;经过测试,发现在3个环境中都没有捕获到;

process.on('unhandledRejection', function (err, p) {
    console.log(err)
})

3:如果promise状态已经变为resolved,再抛出错误也是无效的,并不会被捕获,等于没有输出;注意跟上面的定时器抛出错误的区别;

var promise = new Promise(function (resolve, reject) {
    resolve('OK');
    console.log('haohao')
    throw new Error('TEST1')
})
promise.then(function (value) {
    console.log(value)
}).catch(function (error) {
    console.log(error)
})

这里写图片描述
4:then()方法返回的是一个新的promise实例(注意不是原来的那个promise实例);因此可以采用链式写法:then后面可以再次调用另外一个then方法
5:catch()方法是then(null, rejection)的别名,用于指定发生错误时的回调函数;因此返回的也是一个promise对象;

getJSON('/post.json').then(function () {
    //如果promise对象状态变为resolved,则会调用then方法指定的回调函数
}).catch(function () {
    //如果promise对象状态变为rejected,会调用catch方法指定的回调函数;另外then方法指定的回调函数如果在运行中抛出错误,也会被catch捕获;
})

因此不要在then方法定义rejected状态的回调函数(then的第二个参数),应该总是使用catch方法;
6:写上catch跟不写catch的区别如下:貌似也没啥区别,都不会影响后面代码的执行;退出码是0表示执行成功;
(1)

var someAsyncThing=function () {
    return new Promise(function (resolve,reject) {
        resolve (x+2)
    })
}
someAsyncThing().then(function () {
    console.log('everything is good')
})
console.log('haohao')

这里写图片描述
这里写图片描述
(2)

var someAsyncThing=function () {
    return new Promise(function (resolve,reject) {
        resolve (x+2)
    })
}
someAsyncThing().then(function () {
    console.log('everything is good')
}).catch(function (error) {
    console.log(error)
})
console.log('haohao')

这里写图片描述
这里写图片描述
(3)

var someAsyncThing=function () {
    return new Promise(function (resolve,reject) {
        resolve (x+2)
    })
}
someAsyncThing().catch(function (error) {
    console.log(error)
}).then(function (value) {
    console.log(value)
})

这里写图片描述
(4)没有报错的话,会跳过catch方法,直接执行后面的then方法;

Promise.resolve().catch(function (error) {
    console.log(error)
}).then(function () {
    console.log('carry on')   
})

这里写图片描述
7:Promise.all()用于将多个Promise实例包装成一个新的Promise.allPromise实例;

var promises=[2,3,5,7,11,13].map(function (id) {
    return getJSON('/post/'+id+".json")
})
Promise.all(promises).then(function (posts) {

}).catch(function () {

})

(1)map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
(2)只有6个实例的状态都变成fulfiled,或者其中一个变为rejected,才会调用Promise.all后面的回调函数;
8:Promise.race()
参数:接受一个数组,数组内都是Promise实例
返回值:返回一个Promise实例,这个Promise实例的状态转移取决于参数的Promise实例的状态变化。当参数中任何一个实例率先处于resolve状态时,返回的Promise实例会变为resolve状态。如果参数中任意一个实例率先处于reject状态,返回的Promise实例变为reject状态。
9:Promise..resolve():用户将现有对象转为Promise对象,
(1)如果参数是Promise实例:原封不动返回
(2)如果参数是enable对象(具有then方法的对象),Promise..resolve()会将这个对象转为promise对象,然后立即执行thenable对象的then方法

let thenable={
    then:function (resolve, reject) {
        resolve(42)
    }
}
let p1=Promise.resolve(thenable)
console.log(p1)                  //Promise { <pending> }
p1.then(function (value) {
    console.log(value)           //42
})

(3)参数是一个原始值,或者是一个不具备then方法的对象,或者根本不是对象;那么该方法返回一个新的promise对象,状态为resolved;

var p=Promise.resolve('hello')
console.log(p)      //Promise { 'hello' }
p.then(function (s) {
    console.log(s)      //hello
})

上面的代码生成一个新的promise对象的实例p,由于字符串‘hello’不属于异步操作(判断方法是字符串对象不具有then方法),返回promise实例的状态从生成起就是resolved(已定型);所以回调函数会立即执行;Promise.resolve(‘hello’)的参数会同时传递给回调 函数;
(4)不带有任何参数:
Promise.resolve()的promise对象是在本轮‘事件循环’结束时,而不是在下轮事件循环开始时

var p=Promise.resolve()
console.log(p)      //Promise { undefined }
p.then(function (s) {
    console.log(s)      //undefined
})

setTimeout(function () {
    console.log(three)
})
Promise.resolve().then(function () {
    console.log('two')
})
console.log('one')
//one
//two
//three

10:promise.reject()方法
这个方法的参数会原封不动的作为reject的理由,变成后续方法的参数;

var p=Promise.reject('出错了')
p.then(null,function (s) {
    console.log(s)   //出错了
})


var p1=new Promise((resolve, reject)=> reject('出错了'))
p1.then(null,function (s) {
    console.log(s)   //出错了
})

以下的方法不在ES6中,

1:done():总是处于回调链的尾端,保证抛出任何可能出现的错误;(无论promise对象的回调以then方法还是catch结尾,只要最后一个方法抛出错误,都有可能无法捕捉;)done()方法可以像then一样使用,提供fullfilled , rejected状态的回调函数,也可以不提供任何参数,不管怎么样,done方法都会捕捉到任何可能出现的错误;
实现方式如下:

Promise.prototype.done=function (onFulfiled, onRejected) {
    this.then(onFulfiled, onRejected).catch(function (reason) {
        setTimeout(()=>{ throw  reason},0)
    })
}

2:finally()用于指定不管promise对象最后状态如何都会执行的操作;跟done最大的区别就是:它接受一个普通回调函数作为参数,该函数不管怎么样,都会执行;

Promise.prototype.finally=function (callback) {
    let P=this.constructor
    return this.then(
        value => P.resolve(callback()).then(()=>value),
        reason => P.resolve(callback().then(()=>{ throw reason}))
    )
}

3:实际开发中经常碰到一种情况:不知道或者不想区分函数f是同步还是异步操作。但是想用promise处理它,因为这样就可以不管f是否包含异步操作,都用then方法指定下一步流程,用catch方法处理抛出的错误;

const f=()=>console.log('now')
Promise.resolve().then(f)
console.log('next')
//输出结果
//next
//now

上面的代码函数f是同步的,但是用promise包装以后就变成异步执行了;暂时先不研究
(1)第一种解决办法:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值