重学 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】。文章转载请联系作者。











评论