@duanyubin
2016-02-28T15:40:20.000000Z
字数 5562
阅读 418
javascript
javascript执行在一个线程上,如果同步执行,某些耗时较长的任务会阻塞线程,导致页面停止响应。
所以将这些耗时的任务交由系统其它线程处理,而这些任务完成后,会已事件的方式通知js线程。
Callback hell
回调嵌套,导致可能出现下列的问题。
var MongoClient = require('mongodb').MongoClient,
test = require('assert');
MongoClient.connect('mongodb://localhost:27017/test', function(err, db) {
// Add a user to the database
db.addUser('user', 'name').then(function(result) {
// Authenticate
db.authenticate('user', 'name').then(function(result) {
test.equal(true, result);
// Logout the db
db.logout().then(function(result) {
test.equal(true, result);
// Remove the user from the db
db.removeUser('user').then(function(result) {
// Authenticate
db.authenticate('user', 'name').then(function(result) {
test.equal(false, result);
db.close();
}).catch(function(err) {
db.close();
});
});
});
});
});
});
We have a problem with promises
CAUTION: Support via polyfill
function timeout(duration = 0) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration);
})
}
var p = timeout(1000).then(() => {
return timeout(2000);
}).then(() => {
throw new Error("hmm");
}).catch(err => {
return Promise.all([timeout(100), timeout(200)]);
})
Q: What is the difference between these four promises?
doSomething().then(function () {
return doSomethingElse();
});
doSomething().then(function () {
doSomethingElse();
});
doSomething().then(doSomethingElse());
doSomething().then(doSomethingElse);
注:下文中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...
更好的方式:
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);
});
组合式Promise, then的回调函数中,return 另外一个promise. 在下一个then回调中,前一个异步任务是已完成状态。
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, 意味着第二个函数并不会等待db.remove()
执行完毕才执行。
解决方案: 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()
接受Promise数组作为参数,返回另一个promise,等待所有元素都执行完毕后才resolve.
另外,只要有一个子元素reject,返回的promise就是reject状态。
catch()
这将导致错误不能被捕捉,所以尽量加一个:
somePromise().then(function () {
return anotherPromise();
}).then(function () {
return yetAnotherPromise();
}).catch(console.log.bind(console));
deferred
somePromise().then(function () {
someOtherPromise();
}).then(function () {
// 希望someOtherPromise已经为resolve状态
// 实际上并没有
});
在每个then方法的函数中:
1. return另一个promise
2. return同步的值,或者undefined(尽量保证每个then方法都有return)
3. 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!
});
理解了上述这些,就理解了Promise
Promise.resolve()
不推荐写法:
new Promise(function (resolve, reject) {
resolve(someSynchronousValue);
}).then(/* ... */);
推荐写法:
Promise.resolve(someSynchronousValue).then(/* ... */);
// 同样的
Promise.reject(new Error('some awful error'));
catch
并不完全等于 then(null, ...)
一般的下列二者是等价的:
somePromise().catch(function (err) {
// handle error
});
somePromise().then(null, function (err) {
// handle error
});
但下列并不等价
somePromise().then(function () {
return someOtherPromise();
}).catch(function (err) {
// handle error
});
somePromise().then(function () {
return someOtherPromise();
}, function (err) {
// handle error
});
// 第二个的问题在于
somePromise().then(function () {
throw new Error('oh noes');
}, function (err) {
// I didn't catch your error! :(
});
Promise.resolve('foo').then(Promise.resolve('bar')).then(function (result) {
console.log(result);
});
实际结果为?
问题在于:没有给then方法传递一个函数,这样相当于then(null)
,导致前一个promise的结果传递给第三个。
应该为:
Promise.resolve('foo').then(function () {
return Promise.resolve('bar');
}).then(function (result) {
console.log(result);
});
doSomething().then(function () {
return doSomethingElse();
}).then(finalHandler);
// ======================================================================
doSomething
|-----------------|
doSomethingElse(undefined)
|------------------|
finalHandler(resultOfDoSomethingElse)
|------------------|
doSomething().then(function () {
doSomethingElse();
}).then(finalHandler);
// ======================================================================
doSomething
|-----------------|
doSomethingElse(undefined)
|------------------|
finalHandler(undefined)
|------------------|
doSomething().then(doSomethingElse())
.then(finalHandler);
// ======================================================================
doSomething
|-----------------|
doSomethingElse(undefined)
|---------------------------------|
finalHandler(resultOfDoSomething)
|------------------|
doSomething().then(doSomethingElse)
.then(finalHandler);
// ======================================================================
doSomething
|-----------------|
doSomethingElse(resultOfDoSomething)
|------------------|
finalHandler(resultOfDoSomethingElse)
|------------------|