promise-then 深刻理解异步

异步经常使用的几种方式

setTimeout/EventEmitter/Promise/generator/async-await 今天着重来说解一下 promise数组

setTimeout和Promise队列有何关联

setTimeout(function(){console.log(4)},0); 
new Promise(function(resolve){ 
    console.log(1) 
    for( var i=0 ; i<10000 ; i++ ){ i==9999 && resolve() } 
    console.log(2) })
.then(function(){ console.log(5) });
 console.log(3);

在这里咱们须要先理解We have a problem with promises

doSomething().then(function () {
      return doSomethingElse();
    });
    
    doSomething().then(function () {
      doSomethingElse();
    });
    
    doSomething().then(doSomethingElse());
    
    doSomething().then(doSomethingElse);

promise 在应用的过程当中须要注意的地方

1.new promise (resolve,reject){};必定要resolve,或者reject 出去不要,作反作用函数。
2.then 操做里面 接收 promise 对象,若是在promise里面是执行的纯函数,也能够返回一个 promise。resolve("常量")。避免promise 穿透

正确使用 promise 金字塔代码

新手错误 #1: promise版的金字塔问题
观察你们如何使用 PouchDB 这类大型的 promise 风格的API,我发现大量错误的 promise 使用形式。最多见的错误就是下面这个:promise

remotedb.allDocs({
  include_docs: true,
  attachments: true
}).then(function (result) {
  var docs = result.rows;
  docs.forEach(function(element) {
    localdb.put(element.doc).then(function(response) {
      alert("Pulled doc with id " + element.doc._id + " and added to local db.");
    }).catch(function (err) {
      if (err.status == 409) {
        localdb.get(element.doc._id).then(function (resp) {
          localdb.remove(resp._id, resp._rev).then(function (resp) {

// et cetera...
是的,实际上你能够像使用回调同样使用 promises,恩,就像用打磨机去削脚趾甲同样,你确实能够这么作。缓存

而且若是你觉得这样的错误只限于初学者,那么你会惊讶于我其实是在黑莓官方开发者博客上看到上面的代码。老的回调风格的习惯难以消灭。(至开发者: 抱歉选了你的例子,可是你的例子将会有积极的教育意义)异步

正确的风格应该是这样:async

remotedb.allDocs(...).then(function (resultOfAllDocs) {
  return localdb.put(...);
}).then(function (resultOfPut) {
  return localdb.get(...);
}).then(function (resultOfGet) {
  return localdb.put(...);
}).catch(function (err) {
  console.log(err);
});

这种写法被称为 composing promises ,是 promises 的强大能力之一。每个函数只会在前一个 promise 被调用而且完成回调后调用,而且这个函数会被前一个 promise 的输出调用,稍后咱们在这块作更多的讨论。ide

  • 4.promise 中foreach 操做,转换成 promise.all()=>返回一个数组
  • 5.在任何应用到了promise的过程当中,必定要注意使用catch 将异常抛出来,否则会堵塞整个加载

使用反作用调用而非返回

下面的代码有什么问题?函数

somePromise().then(function () {
  someOtherPromise();
}).then(function () {
  // Gee, I hope someOtherPromise() has resolved!
  // Spoiler alert: it hasn't.
});

好了,如今是时候讨论一下关于 promises 你所须要知道的一切。code

认真的说,这是一个一旦你理解了它,就会避免全部我说起的错误的古怪的技巧。你准备好了么?对象

就如我前面所说,promises 的奇妙在于给予咱们之前的 return 与 throw。可是在实践中这究竟是怎么一回事呢?blog

每个 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() 函数内部 永远返回或抛出 的习惯。我建议你也这样作。

抛出同步异常
谈到 throw,这是让 promises 更加赞的一点。好比咱们但愿在用户已经登出时,抛出一个同步异常。这会很是简单:

getUserByName('nolan').then(function (user) {
  if (user.isLoggedOut()) {
    throw new Error('user logged out!'); // throwing a synchronous error!
  }
  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!
}).catch(function (err) {
  // Boo, I got an error!
});

若是用户已经登出,咱们的 catch() 会接收到一个同步异常,而且若是 后续的 promise 中出现异步异常,他也会接收到。再强调一次,这个函数并不须要关心这个异常是同步仍是异步返回的。

这种特性很是有用,所以它可以在开发过程当中帮助定位代码问题。举例来讲,若是在 then() 函数内部中的任何地方,咱们执行 JSON.parse(),若是 JSON 格式是错误的,那么它就会抛出一个异常。若是是使用回调风格,这个错误极可能就会被吃掉,可是使用 promises,咱们能够轻易的在 catch() 函数中处理它了。

必定要注意咱们在then 函数内部的时候

咱们能够作什么呢?有三种事情:

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

参考资料

相关文章
相关标签/搜索