神刀安全网

深入了解 Promise

Promise 进阶核心

下面部分摘录 We have a problem with promises

每一个 promise 都会提供给你一个 then() 函数 (或是 catch(),实际上只是 then(null, …) 的语法糖)。当我们在 then() 函数内部时

somePromise().then(function () {     // I'm inside a then() function! }); 

我们可以做什么呢?有三种事情:

  • return 另一个 promise
  • return 一个同步的值 (或者 undefined)
  • throw 一个同步异常

就是这样。一旦你理解了这个技巧,你就理解了 promises。因此让我们逐个了解下。

返回另一个 promise

这是一个在 promise 文档中常见的使用模式,也就是我们在上文中提到的 “composing promises”:

getUserByName('nolan').then(function (user) {     return getUserAccountById(user.id); }).then(function (userAccount) {   // I got a user account! }); 

注意到我是 return 第二个 promise,这个 return 非常重要。如果我没有写 returngetUserAccountById() 就会成为一个副作用,并且下一个函数将会接收到 undefined 而非 userAccount

返回一个同步值 (或者 undefined)

返回 undefined 通常是错误的,但是返回一个同步值实际上是将同步代码包裹为 promise 风格代码的一种非常赞的手段。举例来说,我们对 users 信息有一个内存缓存。我们可以这样做:

getUserByName('nolan').then(function (user) {     if (inMemoryCache[user.id]) {     return inMemoryCache[user.id];    // returning a synchronous value!   }   return getUserAccountById(user.id); // returning a promise! }).then(function (userAccount) {   // I got a user account! }); 

是不是很赞?第二个函数不需要关心 userAccount 是从同步方法还是异步方法中获取的,并且第一个函数可以非常自由的返回一个同步或者异步值。

不幸的是,有一个不便的现实是在 JavaScript 中无返回值函数在技术上是返回 undefined,这就意味着当你本意是返回某些值时,你很容易会不经意间引入副作用。

出于这个原因,我个人养成了在 then() 函数内部 永远返回或抛出 的习惯。我建议你也这样做。

实战

将带回调的函数,包装成 Promise

module.exports = fn => {     return (...args) => {     return new Promise((resolve, reject) => {       args.push((err, result, ...other) => {         err ? reject(err) : resolve(result, other)       })       fn(...args)     })   } } 

利用 ES6的新特性,我们仅用10行代码就写出了一个 promisify的函数

Promise 的并行

我们先写一个用来测试使用的异步函数delay,用来延迟100ms 后返回传进来的数字

const delay = number => {     return new Promise((resolve, reject) => {     setTimeout(() => {       resolve(number)     }, 100)   }) } 

promise 的并行非常的简单,我们可以使用 Promise.all来对一个 Promise 数组进行并行。 下面的代码是对一个数组进行并行执行 delay

// 使用 ava 进行测试 import test from 'ava';  const numbers = [1, 2, 3, 4, 5];  test('parallel', async t => {     console.time('parallel');   t.deepEqual(await Promise.all(numbers.map(delay)), numbers);   console.timeEnd('parallel'); }); 

Promise 的串行

Promise 的串行实现起来比较麻烦(而且我也没想到比较好的应用场景),不过实现 Promise 的串行可以让我们非常好的理解 Promise 本身

Promise 实现的原理是我们要实现一个 Promise 顺序执行串

类似这样

promise1.then(data1 => {return promise2(data1)}).then(data2 => {return promise3(data2)})...   

真正的实现如下

// 使用 ava 进行测试 import test from 'ava';  const numbers = [1, 2, 3, 4, 5];  const series = factories => {     // 看懂这行你就明白 Promise 了吧   return factories.reduce((resolve, factory) => resolve.then(number => factory()), Promise.resolve()) }  const factory = number => () => delay(number)  test('serial', async t => {     console.time('serial');   t.is(await series(numbers.map(factory)), numbers[numbers.length -1])   console.timeEnd('serial'); }) 

其他

  • 如果大家对上述代码有疑问,建议仔细看一下 We have a problem with promises
  • 上述代码在代码开源在 learning-promises ,可以下载安装后,跑一下测试用例
  • 如果还有疑问大家可以在下方评论,或者联系我微博、 GitHub

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 深入了解 Promise

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址