上週講了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
找起問題來會特別麻煩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
getUserByName('nolan').then(function (user) {
return getUserAccountById(user.id);
}).then(function (userAccount) {
// I got a user account!
});
複製代碼
注意到我是 return
第二個 promise,這個 return
很是重要。若是我沒有寫 return
,getUserAccountById()
就會成爲一個反作用,而且下一個函數將會接收到 undefined
而非新的 promise
。
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'));
複製代碼
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,個人實例代碼所有是這篇文章的,做者是一個外國大牛,有興趣的能夠去看一下