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,個人實例代碼所有是這篇文章的,做者是一個外國大牛,有興趣的能夠去看一下

相關文章
相關標籤/搜索