promise常见错误

导读

上周讲了promise用法,这周咱们讲一下promise实战中可能出现得一些易错点,若是对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) {}
    }
  })
复制代码

promise得新特性之一就是解决回调地狱问题,因此咱们能够换个更优雅得写法达到上段代码的效果promise

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);
});
复制代码

######常见问题二 : 用了 promises 后怎么用 forEach?bash

/ I want to remove() all docs
db.allDocs({include_docs: true}).then(function (result) {
  result.rows.forEach(function (row) {
    db.remove(row.doc);  
  });
}).then(function () {
  // I naively believe all docs have been removed() now!
});
复制代码

这份代码有什么问题?问题在于第一个then函数实际上返回的是 undefined(入门篇讲过咱们须要手动return),这意味着第二个方法不会等待全部 documents 都执行 db.remove()方法(由于后一个then接收到的undefind并无相似于promise实例状态ejected/fullfilled)。因此他不会等待任何事情,而且可能会在任意数量的文档被删除后执行! 这里咱们须要用 Promise.all()异步

db.allDocs({include_docs: true}).then(function (result) {
  return Promise.all(result.rows.map(function (row) {
    return db.remove(row.doc);
  }));
}).then(function (arrayOfResults) {
  // All docs have really been removed() now!
});
复制代码

上面的代码是什么意思呢?大致来讲,Promise.all()会以一个 promises 数组为输入,而且返回一个新的 promise。这个新的 promise 会在数组中全部的 promises 都成功返回后才返回。一旦数组中的 promise任意一个返回错误,Promise.all() 也会返回错误,他是异步版的 for循环。函数

常见问题三 : 忘记使用 .catch()

咱们在使用程序的时候,不免会出现问题,若是不适用catch找起问题来会特别麻烦ui

somePromise().then(function () {
  return anotherPromise();
}).then(function () {
  return yetAnotherPromise();
}).catch(
err=>{
  thorw new Error(err)
}); 
复制代码
常见问题四 :使用反作用调用而非返回

没有return返回新的promise就会默认返回一个undefind,这就是反作用spa

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

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

somePromise().then(function () {
  // 这里能够作什么???
});
复制代码

咱们能够在这里作三件事情code

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

咱们来看一下这三种事情blog

  • 返回另外一个 promise
getUserByName('nolan').then(function (user) {
  return getUserAccountById(user.id);
}).then(function (userAccount) {
  // I got a user account!
});
复制代码

注意到我是 return 第二个 promise,这个 return 很是重要。若是我没有写 returngetUserAccountById() 就会成为一个反作用,而且下一个函数将会接收到 undefined 而非新的 promise

  • ######返回一个同步值 (或者 undefined) 返回 undefined 一般是错误的,可是返回一个同步值其实是将同步代码包裹为 promise 风格代码的一种很是赞的手段。
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.resolve()/Promise.reject(); 咱们会常常这么使用promise

new Promise(function (resolve, reject) {
  resolve(someSynchronousValue);
}).then(/* ... */);
复制代码

使用 Promise.resolve()会更加简洁

Promise.resolve(someSynchronousValue).then(/* ... */);
复制代码

咱们应该在全部 promise 形式的 API 接口中这样使用它

function somePromiseAPI() {
  return Promise.resolve().then(function () {
    doSomethingThatMayThrow();
    return 'foo';
  }).then(/* ... */);
}
复制代码

任何有可能 throw 同步异常的代码都是一个后续会致使几乎没法调试异常的潜在因素。可是若是你将全部代码都使用 Promise.resolve() 封装,那么你老是能够在以后使用 catch() 来捕获它。 相似的,还有 Promise.reject() 你能够用来返回一个马上返回失败的 promise。

Promise.reject(new Error('some awful error'));
复制代码
promises 穿透
Promise.resolve('foo').then(
  Promise.resolve('bar')
  ).then(function (result) {
  console.log(result); //foo
});
复制代码

之因此会打印foo而不是bar,是由于咱们 Promise.resolve('bar')这段代码有问题,这段代码返回的是一个promise,但咱们并无return

Promise.resolve('foo').then(function () {
  return Promise.resolve('bar');
}).then(function (result) {
  console.log(result);
});
复制代码

固然promise还有一些高级的用法,你们能够去读一下 promise,个人实例代码所有是这篇文章的,做者是一个外国大牛,有兴趣的能够去看一下

相关文章
相关标签/搜索