Promise 几点实战应用

2017-06-11  本文已影响211人  Pober_Wong

简介

长话短说,promise 是 EcmaScript 6 提出的新特性,主要是用来解决异步调用中过度依赖回调的问题(或者说是以链式的调用的方式解决回调地狱的问题)。
// 此处不对 promise 做介绍,有需要的可以去 阮一峰老师的 ES6 教程 看看或者这本 promise迷你书 (更加完善,而且可以在线运行测试代码,荐)

起因

做任何事都是要有起因的,不可能空穴来风,在被折腾了好几番之后,最终决定写下该文,毕竟趟完坑不能自己藏着掖着,把一点心得贡献出来也是非常值得的。

具体细节则主要和三月份对公司项目的那次重构有关。当时自己也是刚入职,面对一个文件中上千行面向过程式、MVC 混为一谈、函数名 r、j、k 式命名的代码让人痛苦不已。为了清晰的了解业务逻辑,技术实现细节以及保证最小可执行单位的稳定性,我和同事花了大半天的时间做了给一千多行的 “劣质代码” 分模块,加注释的工作。因为自己以前还算是对 proimse 颇有心得,就果断使用 promise 处理工作流程了,没想到还是跌到坑里了,不过就目前来讲,都是非常值得的事情。

使用 promise 实现对数据的分层处理

因为 promise 主要使用场景是异步任务,就不用同步任务抬杠了。此处我们主要以请求数据为例展开做介绍。(请求库可以是 request、 superagent、fetch、AJAX 亦或是 jQuery,都没关系)

// 此处拿通过 promise 处理过的 superagent 举例(处理函数为写在原型上的 promisify)
request.get("your api")
.promisefy()
.then(
res => res.text,
error => Promise.reject(error.text)
)

如上代码主要体现了
1. 传递处理后的数据,如这里我们向下级 then 的 resolve、reject 传递了 `res.text `,同样还有 `error.text` // 其实这两个都是被 superagent 处理后两种状态的 response。
2. 对于在 reject 中使用 `Promise.reject(error.text)` 则表现了对状态的保存,譬如当 reject 事件发生后,能够通过返回一个新的 promise (这里仅有 reject 的一个 promise 对象)来连接下一个 then. 其实准确来讲,第一个也应该是 `res => Promise.resolve(res.text)`, 不过鉴于在 promise 机制中,当前方 then 中被执行的回调返回了一个非 promise 对象时,当前 then 的 resolve 回调的参数则会是上一个被执行回调的返回值(不论是 resolve 还是 reject 被执行)。

* 这里我提供一点测试代码  

```javascript
const promiseTest = input => new Promise(resolve, reject) {
  if (input) {
    resolve("success")
  } else {
    reject("failed")
  }
}

使用 race 来给 fetch 实现一个伪超时机制

众所周知,promise 拥有两个最实用的静态方法 —— raceall,二者都接受一个以 promise 数组的参数。

通过以上两个特性,我们就可以通过 race 结合 fetch 以及 setTimeout
来做一个简单的超时机制。

// 使用 setTimeout 封装的 promise
const delay = ms => new Promise(resolve, reject) {
  setTimeout(() => {
    reject(new Error("timeout"))
  }, ms)
}

const fetchWithTimeout  = (ms, ...args) => {
    return Promise.race([fetch(...args), delay(ms)])
}

这样将正常的 fetch 请求和一个 timer 事件进行 race,最先完成的既是运行结果。不过需要注意的一点是:
fetch 请求并不会因此而被终止掉,而是会继续请求

上一篇 下一篇

猜你喜欢

热点阅读