感谢n͛i͛g͛h͛t͛i͛r͛e͛
大大指出的关于Promise
中catch
用的不到位的毛病,贴上大大引荐的文章Promise中的菜鸟和高阶毛病,文章很细致说清晰明了一些Promise
运用中的毛病和指点。别的改正内容在背面补充。
从 jQuery $.Deferred() 最先
说到异步流程掌握,之前用的比较多的是jQ的Deferred。那Deferred是个啥呢,不清晰没紧要,直接掌握台来打印看下:
喔!看得出$.Deferred()后是个对象,其下面有着熟习的done
, fail
, always
字眼(对,,是否是有点熟习了呢?没错!假如经常常使用ajax的话就会常常接触到这些货品)。 固然了,不止这些,另有最最最主要的reject
和resolve
要领,说到这两个要领,就得引出下Deferred的状况机制了——实在很简单,实例化后用上图中的state
要领就能够检察($.Deferred().state()
),有三种状况
实行resolve/reject前,返回值是pending
实行了resolve,返回值是resolved
实行了reject,返回值是rejected
直接来试着用下吧!这里我们假定实行一个随机延时的setTimeout
的异步操纵,在setTimeout
异步操纵终了后,依据延时大小,做出差别回应 ! 代码:
function log (msg) {
console.log(msg);
}
// 包装一个异步操纵
var Async = function () {
// 天生一个0到5秒的耽误
var delay = Math.floor(Math.random() * 5);
// 建立一个Deffered对象
var dfd = $.Deferred();
// 这里挪用一个异步操纵
setTimeout(function(){
if (delay <= 2) {
// 置dfd状况为resolved
dfd.resolve('一切正常!');
} else {
// 置dfd状况为rejected
dfd.reject('超时了!');
}
}, delay * 1000)
// 这里要返回Deferred下的promise对象Dererred对象的缘由下面会诠释
return dfd.promise();
}
Async()
.done(function (data) {
log(data) // 假如耽误不大于三秒 输出dfd.resolve()中的数据 '一切正常!'
})
.fail(function (err) {
log(err) // 反之则 输出dfd.reject()中的数据 '超时了!'
})
.always(function () {
log('实行终了!'); // 老是输出 '实行终了!'
})
尝试下浅显邃晓全部流程就是
在某个操纵最先前建立一个
Deferred
对象,然后实行操纵操纵间可依据状况给dfd实行
relove
或许reject
要领转变状况并传入数据末了返回出dfd的对象下的一个promise对象,这里不直接返回dfd对象是由于dfd对象的状况是在第一次resolve或许reject后还能够变动的(不过内里的数据以第一次为准)!!
操纵实行后用
done
和fail
要领离别吸收resolve和reject状况和数据(一一对应)然后实行回调(实在1.8另有个then
要领,吸收两个参数,第一个参数为resolve
的回调,第二个为reject
的)
always
是不论resolve
照样reject
都邑实行。
讲个比较烂的比方啊
我是一个流水线车间质检工人,就在寻常的如许的一天,来了一批玩具熊,嗯,接下来应当是如许的
来了一个搜检目的(
$.Dererred()
),这时候你还不晓得它是好是坏我靠我几十年的新东方炒菜技能磨练产物并给良品贴上了及格标签(
dfd.res* olve(及格标签)
),次品贴上回厂标签* (dfd.reject(回厂标签及缘由)
)然后经由过程的良品和次品都来到了各自的包装口打好包,不能对内里的标签做变动了!(
dfd.promise()
)去往本身下一个目的地(return dfd.promise
)再然后良品来到了熊孩子手中(
.done()
),次品回到了厂里(.fail()
),末了不论玩具熊到了那里,实在都邑被开膛破肚(.always()
好吧这里有点牵强)
这里再上一张图来诠释下!
另有值得说一下的是always
里的回调,我在现实中运用时发明老是在done
和fail
里的回调(假定为同步)实行终了后后实行的。
金掌银掌仙人掌 掌声有请 ES6 Promise
和上面一样,先打印一下!
能够看到Promise下也有熟习的resolve
和reject
要领,彷佛和jQ的Deferred
很是类似!然则否是少了点什么呢?done
或许fail
之类的流程掌握的要领呢??
不急,实在睁开prototype
原型上就能够看到挂载着的then
要领了!(像极了jQ1.8后谁人then
,不过我认为应当说是jQ来遵照Promise
才对)
Promise实在就是个组织函数,照样之前的例子,这里我们分三步走
var Async = function () {
// 第一步,新建个promise对象,所需的异步操纵在其中举行
var prms = new Promise(function(resolve, reject){
// 天生一个0到5秒的耽误
var delay = Math.floor(Math.random() * 5);
// 这里挪用一个异步操纵
setTimeout(function(){
// 第二步, 依据状况置promise为resolve或许reject
if (delay <= 2) {
// 置dfd状况为resolved
resolve('一切正常!');
} else {
// 置dfd状况为rejected
reject('超时了!');
}
}, delay * 1000)
})
// 第三步,返回这个Promise对象
return prms
}
// 壮大的来了
Async()
// then吸收两个函数离别处置惩罚resolve和reject两种状况
.then(
function(data) {
console.log(data) // 一切正常!
},
function(err) {
console.log(err) // 超时了!!
})
粗粗一看彷佛和Dererred
不能更像了,,不过仔细点的话能够发明我们在函数里直接返回了prms
这个对象,而不是像之前把包装了一层。。。对!由于Promise
的特征就是一旦第一次给予了状况背面就没法变动了,这也算费心多了吧。然则题目来了,我为何要挑选用Promise
呢??
这么说吧,它是原生的 它是原生的 它是原生的!,另有能够链式链式链式链式挪用!,我们能够把每个then
或许catch
当作一个处置惩罚器, 比方如许
Async()
// 这里临时只处置惩罚resolve
.then(function(data) {
console.log(data) // 一切正常!
return Promise.resolve('随意什么');
})
// 下一个then处置惩罚器吸收到上一个处置惩罚器发出的数据
.then(function(data2) {
console.log(data2) // 随意什么
return Promise.reject('毛病数据');
})
...
对!没看错,实在在then
内里你还能够return
其他的promise
对象传并递数据!更有甚你以至能够什么都不返回,比方说如许
Async()
.then(function(data) {
console.log(data) // 一切正常!
})
// 上面谁人处置惩罚器假如不return任何东西 就会默许返回个resolve(undefined)
// 然后下面的处置惩罚器就会吸收到这个resolve(undefined)
.then(function(data2) {
console.log(data2) // undefined
// 虽然没有数据来处置惩罚,然则你还能够在这里做一些事变啊,比方
return Promise.reject('毛病数据');
})
// 嗒哒,catch就这么上台了,这里用catch处置惩罚上个then处置惩罚器发出的reject
.catch(fucntion(err){
console.log(err) // 毛病数据
return '那直接返回个字符串呢?'
})
// 上个catch处置惩罚器返回了个字符串实在也会被下个处置惩罚器吸收
// 相当于resolve('那直接返回个字符串呢?')
.then(function(data3){
console.log(data3) // 那直接返回个字符串呢?
})
// 好,接着我们来尝尝在没有返回任何东西的状况下接一个catch处置惩罚器
.catch(function(err2){
console.log(err2)
// 我们能够来猜一下上面会输出什么,undefined吗?
// 错,实在这里什么都不会输出,由于这个catch吸收的是resolve
// 但它并不会淹没这个resolve而是挑选跳过,比方我们这里再返回
return Promise.resolve('这个字符串会被跳过')
})
// 这里紧接着个then处置惩罚器,它吸收到的数据呢
// 实在并非上个catch返回的resolve('这个字符串会被跳过')
// 而是catch之前谁人then处置惩罚器默许返回的resolve(undefined)
.then(function(data4){
console.log(data4) // undefined
})
有点被绕晕了吧
我们用一句话来梳理下:
链式调下会有一串then
和catch
,这些then
和catch
处置惩罚器会根据递次吸收上个处置惩罚器所发作的返回值,而且依据传入的状况做出差别相应,要么跳过,要么处置惩罚(所以上面23行处的catch
处置惩罚器被跳过了)
ps: 上面我们用的then
处置惩罚器只要一个函数参数,所以只会处置惩罚resolve
状况,假如是两个then
就能够处置惩罚reject
了。
----更新于5月11日-----
catch
运用的注重
上面一块代码中引出了catch
处置惩罚器, 之前认为 cacth()
是 then(null, ...)
的语法糖, 实在这么说不完全准确(功用层面上来讲这两个是完全相同的没错——都是处置惩罚reject
和非常),然则到了现实运用中Promise中的菜鸟和高阶毛病文章中给出了邃晓的状况证实,这里贴一下:
起首只处置惩罚非常状况,下面两个是等价的
somePromise().catch(function (err) {
// 处置惩罚非常
});
somePromise().then(null, function (err) {
// 处置惩罚非常
});
然则,假如不只是处置惩罚非常的下面两种状况下就不一样了
somePromise().then(function () {
return otherPromise();
}).catch(function (err) {
// 处置惩罚非常
});
somePromise().then(function () {
return otherPromise();
}, function (err) {
// 处置惩罚非常
});
不够清晰吗?那末假如是如许呢?假如第一个回调函数抛出一个毛病
会发作什么?
somePromise().then(function () {
throw new Error('这里错了!');
}).catch(function (err) {
console.log(err)
// 这里错了! :)
});
somePromise().then(
function () {
throw new Error('这里错了');
},
function (err) {
console.log(err)
// 未知 :(
// 并没有catch到上面谁人Error
});
结论就是,当运用 then(resolveHandler, rejectHandler)
, rejectHandler
不会捕捉在 resolveHandler
中抛出的毛病!
贴完了,好吧,这有什么用呢?
看似这个注重项并不影响寻常运用,原文作者也说道:
由于,笔者的个人习气是从不运用then要领的第二个参数,转而运用 catch() 要领
那末,题目来了,怎样准确的运用catch
呢? 实在我没有很好的想邃晓,愿望指教
,随意抛两个砖
// 1
somePromise()
.then(resolveHandler)
// 这个catch会处置惩罚somePromise或许resolveHandler的非常
.catch(rejectHandler)
.then(otherResolveHandler)
// 而这个catch呢只会处置惩罚resolveHandler的非常
.catch(otherRejectHandler)
// 2
somePromise()
.then(resolveHandler)
.then(otherResolveHandler)
// 至于这个catch则会处置惩罚somePromise、resolveHandler和otherResolveHandler的非常
.catch(rejectHandler)
// 3
somePromise()
.catch(console.log.bind(console))
//等价于
.catch(function(err){
console.log(err)
})
哈哈哈哈哈哈,照样好好再去想一想Promise去了,弄邃晓了再来补充,再次感谢@n͛i͛g͛h͛t͛i͛r͛e͛大大,荆柯刺秦王
写的很粗拙,有毛病的处所愿望多多指教!!