We have a problem with promises
http://fex.baidu.com/blog/2015/07/we-have-a-problem-with-promises/ http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
一、新手错误
Promise with forEach
// 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!
});
这份代码有什么问题?问题在于第一个函数实际上返回的是 undefined,这意味着第二个方法不会等待所有 documents 都执行 db.remove()。实际上他不会等待任何事情,并且可能会在任意数量的文档被删除后执行!
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!
});
使用副作用调用而非返回
// 错误
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 () {
// I'm inside a then() function!
});
我们可以做什么呢?有三种事情:
-
return 另一个 promise
-
return 一个同步的值 (或者 undefined)
-
throw 一个同步异常
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!
});
上面这段代码非常重要!
二、谜题揭晓
puzzle 1
doSomething().then(function () {
return doSomethingElse();
}).then(finalHandler);
doSomething
|-----------------|
doSomethingElse(undefined)
|------------------|
finalHandler(resultOfDoSomethingElse)
|------------------|
puzzle 2
doSomething().then(function () {
doSomethingElse();
}).then(finalHandler);
doSomething
|-----------------|
doSomethingElse(undefined)
|------------------|
finalHandler(undefined)
|------------------|
puzzle 3
doSomething().then(doSomethingElse())
.then(finalHandler);
doSomething
|-----------------|
doSomethingElse(undefined)
|---------------------------------|
finalHandler(resultOfDoSomething)
|------------------|
puzzle 4
doSomething().then(doSomethingElse)
.then(finalHandler);
doSomething
|-----------------|
doSomethingElse(resultOfDoSomething)
|------------------|
finalHandler(resultOfDoSomethingElse)
|------------------|