Promise是一个很简单的概念,也许你还没有来得及使用,但你一定了解过这个概念。Promise是一个非常有用的结构,使异步代码更具可读性。而不会产生多层匿名函数的嵌套,使结构非常混乱。这篇文章将会介绍6个与Promise有关的注意事项。
在潜心研究之前,先展示一下如何使用javascript promise:
var p = new Promise(function(resolve, reject) { resolve("hello world"); }); p.then(function(str) { alert(str); });
1. then() 返回新的promise
如下两段代码:
// 示例1 var p = new Promise(/*...*/); p.then(func1); p.then(func2);
// 示例2 var p = new Promise(/*...*/); p.then(func1) .then(func2);
如果你认为上面两段代码的含义是一样的,那么你对promise的认识只限于一维数组的回调方式。实际上每调用一次then()就会返回一个新的promise。的示例1中,如是func1抛出一个错误,func2仍会被正常调用。
在示例2中,如果func1抛出一个错误,func2将不会被调用。因为第一次调用then()时返回的新的promise由于func1的错误而没有被返回。所以func2将会被跳过。
提示:promise可以实现复杂的多分支结构。
2.在回调间传递结果
如下面的代码:
var p = new Promise(function(resolve, reject) { resolve("hello world"); }); p.then(function(str) {}) .then(function(str) { alert(str); });
上面的代码第二个then()中的alert将不能弹出任何信息。因为在第一个then()中没有将结果传递到后面的then().promist模式预期每个回调函数都返回相同结果或者替代者,这个结果将会被传递给下一个回调函数。
这种想法类似于使用适配器来变换结果,如下面示例:
var feetToMetres = function(ft) { return ft*12*0.0254 }; var p = new Promise(/*...*/); p.then(feetToMetres) .then(function(metres) { alert(metres); });
3.捕抓前级的异常。
比较一下下面两个代码有什么不同:
在示例A中,第一个then()中抛出一个异常,在第二个then()当中将会捕捉到这个异常,并会输出”哈哈”。
// 示例 A new Promise(function(resolve, reject) { resolve("hello world"); }) .then( function(str) { throw new Error("哈哈"); }, undefined ) .then( undefined, function(error) { alert(error); } );
// 示例 B new Promise(function(resolve, reject) { resolve("hello world"); }) .then( function(str) { throw new Error("哈哈"); }, function(error) { alert(error); } );
在示例B中,异步回调函数和异常回调函数都在一起。这时当回调函数抛出异常时,异常回调不会捕捉到异常。实际上示例B中的异常回调函数只有在拒绝模式或promise本身抛出异常的情况下才会运行。
4.异常可以跳过
如果在一个异常回调函数中没有重新抛出异常,则promise认为异常被恢复返回到正常状态。下面的示例当中,将会弹“显示我,哈哈!”。因为在该示例中第一个then()中的异常回调没有重新抛出异常。
var p = new Promise(function(resolve, reject) { reject(new Error("pebkac")); }); p.then( undefined, function(error) { } ) .then( function(str) { alert("显示我,哈哈!"); }, function(error) { alert("不能显示我"); } );
5.promise可以暂停
如果你想暂停当前的promise继续执行下一个then(),或等待其他任务的完成,你就可以用这种办法,如下面的代码所示:
var p = new Promise(/*...*/); p.then(function(str) { if(!loggedIn) { return new Promise(/*...*/); } }) .then(function(str) { alert("完成"); })
在第一个then()当中return一个新的promise.这样只有直到这个新的promise启动后,才会执行第二个then().弹了“完成”对话框。如上代码所示,当检测到用户的登录session过期后,通过第二个promise弹出登录框让用户登录后再继续执行第二个then()中的动作。
6.promise不是立即执行的。
function runme() { var i = 0; new Promise(function(resolve) { resolve(); }) .then(function() { i += 2; }); alert(i); }
如上代码所示,你可能认为将会弹出2,但是promise是异步调用。所以代码不是顺序执行的。所以alert会弹出0;