@duanyubin
2016-02-28T15:40:20.000000Z
字数 5562
阅读 469
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 databasedb.addUser('user', 'name').then(function(result) {// Authenticatedb.authenticate('user', 'name').then(function(result) {test.equal(true, result);// Logout the dbdb.logout().then(function(result) {test.equal(true, result);// Remove the user from the dbdb.removeUser('user').then(function(result) {// Authenticatedb.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 docsdb.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)|------------------|