Nested Promise(嵌套的Promise)
loadSomething().then(function(something) {
loadAnotherthing().then(function(anthor) {
DoSomethingOnThem(something, anthor);
})
})
你这样书写的原因是需要对2个promise
的结果进行处理,由于then()
接收的是上一个promise返回的结果,因此你无法通过链式写法将其连接起来。
To Fix:
q.all([loadSomething(), loadAnotherThing()])
.spread(function(something, another) {
DoSomethingOnThem(something, another);
})
q.all()
方法将会等待loadSomething
和loadAnotherThing
都被resolve
后调用传入spread
方法里面的回调。
The Broken Chain(断掉的promise链)
先看一段代码:
function anAsyncCall() {
var promise = doSomethingAsync();
promise.then(function() {
somethingComplicated();
})
return promise;
}
这种写法的问题是当somethingComplicated
方法中抛出错误无法被捕获。Promise
应当是链式的,每次调用then()
方法后都会返回一个新的promise
。普遍的写法是:最后调用catch()
方法,这样在前面的一系列的promise
操作当中,发生的任何error
都会被捕获。
上面的代码中,当你最后返回的是第一个promise
,而非这个promise
调用then()
方法后的结果,那么promise
链也随即断掉。
To Fix:
function anAsyncCall() {
var promise = doSomethingAsync();
return promise.then(function() {
somethingComplicated()
});
}
The Collection Kerfuffle
当你有一个数组,数组里面的每个项目都需要进行异步的处理。因此你可能会通过递归去做某些事情:
function workMyCollection(arr) {
var resultArr = [];
function _recursive(idx) {
if (idx >= resultArr.length) return resultArr;
return doSomethingAsync(arr[idx]).then(function(res) {
resultArr.push(res);
return _recursive(idx + 1);
});
}
return _recursive(0);
}
这段代码第一眼看上去有点难以理解啊。主要是的问题是如果不知道还有map
或者reduce
方法,那么你也不会知道有多少个项目需要被链接起来,这样就比较蛋疼了。
To Fix:
上面提到的q.all
方法接受一个数组,这个数组里面都是promise
,然后q.all
方法等待所有这些promise
全部被resolve
后,得到一个数组,由之前的promise
被resolve
后的值组成。这个时候我们可以通过map
方法去改进上面的代码:
function workMyCollection(arr) {
return q.all(arr.map(function(item) {
return doSomethingAsync(item);
}));
}
上面的递归写法是串行处理的,但是通过q.all
和map
进行改写后变成并行处理,因此更加高效。
如果你确实需要promise
串行处理,那么你可以使用reduce
方法:
function workMyCollection(arr) {
return arr.reduce(function(promise, item) {
return promise.then(function(result) {
return doSomethingAsyncWithResult(item, result);
}, q());
});
}
虽然不是很整洁,但是肯定有条理。
The Ghost Promise
有个方法有时需要异步进行处理,有时可能不需要。这时也可以创建一个promise
,去保证2种不同的处理方式的连贯性。
var promise ;
if(asyncCallNeeded) {
promise = doSomethingAsync();
} else {
promise = Q.resolve(42);
}
promise.then(function() {
doSomethingCool();
});
还有一种更加整洁的写法,就是使用Q()
方法去包裹一个普通值
或者promise
。
Q(asyncCallNeeded ? doSomethingAsync() : 42)
.then(function(value) {
dosomethingGood();
})
.catch(function(err) {
handleTheError();
});
The Overly Keen Error Handler
then()
方法接收2个参数,fullfilled handler
以及rejected handler
:
somethingAync.then(function() {
return somethingElseAsync();
}, function(err) {
handleMyError(err);
})
但是这种写法存在一个问题就是如果有错误在somethingElseAsync
方法中抛出,那么这个错误是无法被error handler
捕获的。
这个时候需要将error handler
单独注册到then()
方法中。
To Fix:
somethingAsync
.then(function() {
return somethingElseAsync()
})
.then(null, function(err) {
handleMyError(err);
});
或者使用catch()
方法:
somethingAsync()
.then(function() {
return somethingElseAsync();
})
.catch(function(err) {
handleMyError(err);
});
这2种写法都为了保证在promise
链式处理过程中出现错误能被捕获。
The Forgotten Promise
你调用了一个方法并返回了一个promise
。然而,你忘记了这个promise
并且创建了一个你自己的:
var deferred = Q.defer();
doSomethingAsync().then(function(res) {
res = manipulateMeInSomeWay(res);
deferred.resolve(res);
}, function(err) {
deferred.reject(err);
});
return deferred.promise(;
这里面存在着很多无用的代码,并且和Promise
简洁的思想正好相悖。
To Fix:
return doSomethingAsync().then(function(res) {
return manipulateMeInSomeWay(res);
});
相关资料:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。