重学 JS | 异步编程 Promise
我们都知道 JavaScript 是属于“单线程”语言,一次只能完成一件任务,不能同时执行多个 js 代码任务。倘若存在耗时的任务,后续任务只能排队等待,这将拖延整个程序的执行,导致页面卡顿,甚至造成页面假死。为了解决这个问题,JavaScript 语言引入了同步任务和异步任务,本文讲讲异步编程。
callback()回调函数
首先看看采用callback()
回调函数处理异步。Ajax 异步请求可能是最常见的异步编程了。看下例子:
倘若存在多个嵌套请求,代码将陷入“回调地域”。导致的问题有:
代码臃肿,可读性差
代码耦合度高、可维护性差、难以复用
回调函数都是匿名函数,不方便复用
下面看看 ES6 的Promise
,为异步编程提供了更合理的解决方案。
Promise 生命周期
Promise 对象存在三种状态,进行中(pending),已成功(fulfilled)和已失败(rejected)。Promise 创建时处于pending
状态,状态的改变只能两种可能。一种是成功的时候,将pending
状态改变为fulfilled
;另一种是失败时将状态改变为rejected
。
Promise 执行顺序
Promise 创建后会立即执行,输出 1。
执行
resolve()
函数,触发then()
函数指定的回调函数,但是它要等当前线程中的同步代码执行完毕,因此依次输出 2,再输出 4当所有同步代码执行完毕,执行
then()
函数,此时存在两个回调,依次执行输出 3、5。
Promise 处理异常
我们通常建议使用catch()
去捕获Promise
异常,这就使catch()
函数和then()
函数成对出现,catch()
接收的就是执行rejected()
函数传递的参数。
为啥建议采用catch()
函数呢?看个例子
这个例子里then()
函数的第二个函数不能捕获第一个函数抛出的异常,而catch()
函数能捕获到第一个函数的异常,这就是建议采用catch()
处理rejected
状态的原因。
Promise.all()
p 的状态由all()
函数接收的所有 Promise 状态决定,只有所有接收的 Promise 实例状态都变为 fulfilled,则 p 的状态才会变成fulfilled
。其中存在一个rejected
状态,则 p 状态为rejected
。需要注意的是当接收的 Promise 实例已经定义了catch()
函数,则其rejected
状态会自行捕获消化,并不会触发Promise.all()
函数的catch()
函数。
Promise.race()
如果接收的多个 Promise 实例中任何一个实例变化,那么 p 实例的状态就随之改变,最先改变的那个 Promise 实例返回值将作为实例 p 的回调函数入参。
可以实现这么个场景,Ajax 请求 3s 未收到请求成功响应,则自动处理成请求失败。
Promise.resolve()
将传入的变量转换为 Promise 对象,等价于在 Promise 函数内调用resolve()
函数。
Promise.resolve()
函数执行后,Promise 的状态会立即变为fulfilled
,然后进入then()
函数中处理。
Promise.reject()
函数一样,只不过进入的是catch()
函数。这里不再叙述。
至此,我们大体学习了异步编程之一的 Promise。
版权声明: 本文为 InfoQ 作者【梁龙先森】的原创文章。
原文链接:【http://xie.infoq.cn/article/ddd21564111853c36b18b306a】。文章转载请联系作者。
评论