Promise是什么
Promise是抽象异步处理对象以及对其进行各种操作的组件。听起来很晦涩?没关系,我们慢慢分析。从字义层面解释,Promise对应未来的含义,正如音译普罗米修斯,含义为“先知”的希腊神话故事中的英雄。那“未来”和js有什么关系呢?Js开发者都知道,前端开发中有个非常重要的概念和技术:Ajax请求——Js中的异步操作。而Promise就是对类似的异步处理对象和处理规则进行规范化,并要求采用统一接口进行开发,否则就会报错。
Promise并不是从JavaScript中发祥的概念。它最初被提出是在E语言中, 是基于并列/并行处理设计的一种编程语言。ES6提出了很多新的Js规范,其中Promise就是一个非常引人注目的技术。下面我们简单的探讨和学习Javascript Promise技术。
浏览器支持
桌面浏览器对Promise的支持如下:
Promise如何让Ajax回调更加美丽?
概念的描述可能对Promise的理解还是不深刻,这里我们对比下普通的Ajax写法和使用Promise对象的异步请求方法,这样更能有助于我们理解什么是Promise,以及为什么要使用Promise。
常见的ajax异步请求如下:
由上面代码可以看到开发过程中经常遇到的一个问题,多个异步请求需要按照一定的先后顺序嵌套使用。这种写法会导致多个回调函数嵌套,导致代码不够直观,就是常说的 Callback Hell。为了解决上述的问题,Promise 对象应运而生,在 EMCAScript 2015 当中已经成为标准。
那Promise会怎么做呢?
这样就避免了多重回调嵌套了。
resolve和reject
同样用示例来说明。首先,创建一个用Promise把XHR处理包装起来的名为 getURL 的函数。
从代码可以看出,getURL函数只有在通过XHR取得结果状态为200时才会调用 resolve。也就是只有数据取得成功时,而其他情况(取得失败)时则会调用 reject 方法。
resolve 方法可以使 Promise 对象的状态改变成成功,同时传递一个参数用于后续成功后的操作,即then获取参数进行操作。reject 方法则是将 Promise 对象的状态改变为失败,同时将错误的信息传递到后续错误处理的操作,即catch获取参数进行操作。
所以getURL发送ajax请求如果数据收取成功,则会运行console.log(req.responseText),否则运行console.error(new Error(req.statusText))。
Promise 的三种状态
用new Promise 实例化的promise对象有以下三个状态:
“has-resolution” - Fulfilled:resolve(成功)时。此时会调用 onFulfilled
“has-rejection” - Rejected:reject(失败)时。此时会调用 onRejected
“unresolved” - Pending:既不是resolve也不是reject的状态。也就是promise对象刚被创建后的初始化状态等
getURL例子中的then方法就是根据 Promise 对象的状态来确定执行的操作,resolve 时执行第一个函数(onFulfilled),reject 时执行第二个函数(onRejected)。
三种状态逻辑关系如下图所示:
then 和 catch
上面的例子已经让我们认识了.then().catch()的链式写法,其实在Promise里可以将任意个方法连在一起作为一个方法链(method chain)。下面我们增加方法链长度:
上面代码中的promise chain的执行流程,如果用一张图来描述一下的话,像下面的图那样。
我们可以这样理解:
then:注册onFulfilled时的回调函数
catch:注册onRejected时的回调函数
Promise.all 和 Promise.race
Promise.all 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then 方法。这使得我们在开发过程遇到的异步请求全部完成后再进行操作的需求变得简单方便。
|
|
在上面的代码中,request.comment() 和 request.people() 会同时开始执行,而且每个promise的结果(resolve或reject时传递的参数值),和传递给 Promise.all 的promise数组的顺序是一致的。也就是说,这时候 .then 得到的promise数组的执行结果的顺序是固定的,即 [comment, people]。
接着我们来看看和 Promise.all 类似的对多个promise对象进行处理的 Promise.race 方法。
它的使用方法和Promise.all一样,接收一个promise对象数组为参数。Promise.all 在接收到的所有的对象promise都变为 FulFilled 或者 Rejected 状态之后才会继续进行后面的处理, 与之相对的是 Promise.race 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。
|
|
上面的代码创建了4个promise对象,这些promise对象会分别在1ms,32ms,64ms和128ms后变为确定状态,即FulFilled,并且在第一个变为确定状态的1ms后, .then 注册的回调函数就会被调用,这时候确定状态的promise对象会调用 resolve(1) 因此传递给 value 的值也是1,控制台上会打印出1来。
小结
这里我们对Promise 进行了大概的介绍,感兴趣的同学可以关注JavaScript Promise迷你书(中文版)