You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constpromise=newPromise(function(resolve,rejected){resolve('ok');thrownewError('test');});promise.then(function(value){console.info(value);}).catch(function(error){console.info(error);});// ok
被吃掉的错误
如果没有使用 catch 方法指定错误处理程序,Promise 对象抛出的错误不会传递到外层代码。
constdoAsyncThing=function(){returnnewPromise(function(resolve,rejected){resolve(x);});};doAsyncThing().then(function(value){console.info(value);});setTimeout(()=>{console.info(222);},1000);// Uncaught (in promise) ReferenceError: x is not defined// 222
如果一个 Promise 实例后面有多个 then 方法调用,resolve 和 reject 的结果会一直传递到后面的 then 方法中吗?
constpromiseResolve=newPromise(function(resolve,reject){resolve("resolve value");});promiseResolve.then((data)=>{console.info('first then data:',data);}).then((data)=>{console.info('second then data:',data);}).then((data)=>{console.info('third then data:',data);});
结果
// first then data: resolve value// second then data: undefined// third then data: undefined
constpromiseReject=newPromise(function(resolve,reject){reject("reject value");});promiseReject.then((data)=>{console.info('first then data:',data);},(reject)=>{console.info('first then reject:',reject);}).then((data)=>{console.info('second then data:',data);},(reject)=>{console.info('second then reject:',reject);}).then((data)=>{console.info('third then data:',data);},(reject)=>{console.info('third then reject:',reject);}).catch((err)=>{console.info('catch:',err);})
结果
// first then reject: reject value// second then data: undefined// third then data: undefined
中断 then
当有多个 then 时,如果前面的 then 逻辑不走通就不执行后面 then 逻辑,如何实现?
constpromiseBreak=newPromise(function(resolve,reject){resolve('ok');});promiseBreak.then(()=>{thrownewError('first then error');}).then(()=>{thrownewError('second then error');}).catch((err)=>{console.info('err',err);});// err Error: first then error
使用 return
在函数中使用 return 就会退出函数,在 Promise 中使用 return 结果会如何?
constpromiseReturn=newPromise(function(resolve,reject){returnresolve("ok");resolve("yes");});promiseReturn.then((data)=>{console.info('first then data:',data);}).then((data)=>{console.info('second then data:',data);return'second data';}).then((data)=>{console.info('third then data:',data);});
结果
// first then data: ok// second then data: undefined// third then data: second data
目录
引子
在回顾异步编程相关的知识时,发现
Promise
里面相关的东西,比实际使用 API 要多的多。在网上也查询了一些相关的资料,虽然标准里面都已经写好了,但每篇给人的感觉还是不一样,所以整理一篇符合自己感觉的总结。异步
在 JavaScript 中异步机制还是很常用的,比如请求使用的
ajax
、setTimeout
延时处理、打印日志的console
。在使用异步时,表现出来的是现在运行的一部分和将来运行的一部分之间的关系。在“现在”和“将来”之间的这段空隙,在很多的程序中都需要考虑如何管理。在 JavaScript 中使用了“事件循环”的机制来处理异步。所有异步任务会进入到“任务队列”,一旦有事件需要运行,事件循环就会运行,直到队列清空。用户交互、IO 和定时器会向事件队列中加入事件。任意时刻,一次只能从队列中处理一个事件。执行事件的时候,可能直接或间接的引发一个或多个后续事件。
回调
在处理异步逻辑时,最常用的方式是回调。回调在异步中的使用有两个主要缺陷:缺乏顺序性和可信任性。
缺乏顺序性
工作过一段时间的人,很有可能遇到这样的代码:
这种代码常被称为回调地狱,在维护和阅读时,都需要花费相当的精力。
缺乏可信任性
看下面一个例子:
在这段程序中,
doSomethingA
和doSomethingB
发生在现在,在主程序的控制下,而doSomethingC
发生在将来,在第三方的控制下。这种把自己程序一部分的执行控制交给某个第三方的情况,被称为控制反转。一段时间过后,在某一天,有人反馈doSomethingC
重复执行了 3 次。为了防止这种情况,进行了下面的处理:这样似乎就解决了问题,但再想一想,就会发现还可能出现下面的问题:
为此,我们需要构建对应的机制,针对这些情况进行处理,不管是自己控制下的代码,还是第三方的代码。这些看似合理的处理,表现出来的是回调缺乏可信任性。
如果我们把控制反转再反转回来,希望第三方给我们提供了解任务何时结束的能力,然后由我们自己的代码决定接下来要做的事情,那将会是样?这就是
Promise
要做的事情。Promise
Promise
是一个对象,是用来保存延期(可能是异步)计算结果的一个容器。任何
Promise
对象拥有下面三种状态中的一种:Promise
构造函数接收一个函数作为参数,该函数的第一个参数用于标识Promise
已经完成(从pending
变为fulfilled
)。第二个参数用于标识Promise
被拒绝(从pending
变为rejected
)。下面假设异步操作成功,看下返回的是什么。可以看到,返回对象中有个存储目前
Promise
状态的PromiseStatus
字段,还有存放值的字段PromiseValue
。Promise 缺点
Promise
并为其注册完成或拒绝函数,无法取消程序的执行。Promise
内部报错不会反应到外部。pending
状态时,无法得知目前进展到那一个阶段。Properties of the Promise Prototype Object
在上面打印的值中,还可以发现
__proto__
上的几个方法:then、catch、finally 。then
then
方法的作用是为Promise
实例添加状态改变时的回调函数。then
方法的第一个参数是fulfilled
状态的回调函数,第二个参数是rejected
状态的回调函数。下面看一个例子。可以发现,
then
方法返回了一个新的Promise
实例,因此可采用链式写法。上面的代码指定了两个回调。第一个回调函数完成后,会将结果作为参数,传入第二个回调函数里面。
使用
then
方法链式调用减轻了回调地狱的问题,但仍然有大量重复样板代码。catch
catch
方法用于指定发生错误时的回调函数。在上面的的代码中,如果异步操作抛出错误,状态就会变成
rejected
,就会调用catch
方法指定的回调函数。如果then
方法指定的回调函数,如果在运行中抛出错误,也会被catch
方法捕获。无效的错误
如果
Promise
状态已经变成fulfilled
,再抛出错误无效。因为Promise
的状态一旦改变,就永久保持该状态,不会再变了。被吃掉的错误
如果没有使用
catch
方法指定错误处理程序,Promise
对象抛出的错误不会传递到外层代码。可发现,出现了语法错误,浏览器打印出了错误提示,但并没有退出程序或中止脚本执行,后面还是打印了
222
。也就是说Promise
内部的错误不会影响到外部的代码。推荐写法
then
里面定义reject
状态的回到函数,总是使用catch
。Promise
对象后面要有catch
方法,这样可以处理内部发生的错误。finally
finally
方法用于指定不管Promise
对象最后状态如何,都会执行的操作。Properties of the Promise Constructor
在
__proto__
对应值的属性constructor
中有几个方法:all、race、reject、resolve 。all
在经典的编程术语中,有一种机制叫门(gate),要等待两个或更多并行/并发的任务都完成才能继续。完成的顺序并不重要,但必须都完成,门才能打开让流控制继续,在 Promise API 中,这种模式成为
all
。all
方法接收一个参数,是一个数组,数组中都是Promise
实例。如果参数中某个
Promise
实例 A 定义了自己的catch
方法,当 A 被rejected
,不会出触发Promise.all
的catch
方法。race
race
方法接收一个参数,是一个数组。只要 p1、p2、p3 之中有一个实例率先改变状态,
promiseRace
的状态就会跟着改变。那个率先改变的Promise
实例的返回值,就传递给promiseRace
的回调函数。resolve
resolve
常用来创建一个已完成的Promise
。resolve
方法的参数有以下情况:不带任何参数
直接返回一个
fulfilled
状态的Promise
对象。参数是一个
Promise
实例不做任何改动,直接返回。
参数是一个
thenable
对象thenable
对象只具有then
方法的对象。resolve
方法会将这个对象转化为Promise
对象,然后立即执行对象的then
方法。4.参数不具有
then
方法的对象,或者不是对象这种情况,
resolve
方法会返回一个新的Promise
对象,状态为fulfilled
。由于数字
123
不属于异步操作,返回的Promise
实例从一生成就是fulfilled
,所以回调函数立即执行。reject
reject
方法也会返回一个新的Promise
实例,该实例的状态为rejected
。reject
方法的参数,会原封不动地作为reject
的理由,变成后续方法的参数。这一点与resolve
方法不一致。问题
then 中数据传递
如果一个 Promise 实例后面有多个 then 方法调用,resolve 和 reject 的结果会一直传递到后面的 then 方法中吗?
结果
结果
中断 then
当有多个 then 时,如果前面的 then 逻辑不走通就不执行后面 then 逻辑,如何实现?
使用 return
在函数中使用 return 就会退出函数,在 Promise 中使用 return 结果会如何?
结果
参考资料
The text was updated successfully, but these errors were encountered: