关于Promises的六个秘密
发布在每天学点javascript2014年2月20日view:7011
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

enter image description here

Promises是一个非常简单的概念,即使你之前从没使用过它,你现在就可以马上学会。Promise可以使得异步代码被组织为更具有可读性的结构,从而避免我们编写一堆嵌套的匿名函数代码。本文将讲述六个关于Promise的小秘密。

在深入讲述之前,我们先来快速的回忆一下JavaScript原生Promise代码应该是怎样的:

var p = new Promise(function(resolve,reject){
    resolve('hello world');
});   

p.then(function(str){
    alert(str); 
});   

1.then()返回一个分叉的Promise(forked promise)

你能看出下面两段代码有什么不同吗?

var p = new Promise(/*...*/);   
p.then(func1);
p.then(func2);   

var p = new Promise(/*...*/);   
p.then(func1)
 .then(func2);   

如果你认为两段代码是等价的,那么你可能认为promise仅仅就是一维回调函数的数列。然而,事实并非如此。每次我们调用then()时都会返回一个分叉的promise。因此,在第一段代码中,如果func1()抛出一个异常,func2依然会正常被调用。

在第二段代码中,如果func1()抛出一个异常,func2()将不会被调用,因为第一次调用then()返回了一个新的promise,由于func1()中的异常这个promise被rejected。结果是func2()被跳过不执行。

小贴士:Promise可以像是复杂的流行图一样被分叉为不同的分支。

2.回调函数应该传递结果

当你运行下面的代码时会alert什么结果?

var p = new Promise(function(resolve,reject){
    resolve('hello world'); 
});  

p.then(function(str){})
 .then(function(str){
    alert(str);
 });   

事实上,第二个then()中的alert什么都不会显示。这是因为在promise上下文中的回调函数并不能像一般回调函数那样传递结果。promise希望你的回调函数返回一个结果或是替代品,这个结果会被传递给下一个回调函数。

这样的思想和使用适配器传递一个结果很类似,如下面的代码所示:

var feetToMetres = function(ft){return ft*12*0.0254};   

var p=newPromise(/*...*/);

p.then(feetToMetres)
 .then(function(metres){ 7  alert(metres);
  });   

3.只有上一级的异常能被捕获

下面两段代码有什么区别?

new Promise(function(resolve,reject){
    resolve('hello world');
}).then(
    function(str){
     throw new Error('uh oh');
    }
,undefined)
    .then(undefined,
    function(error){alert(error);
    }
);   

new Promise(function(resolve,reject){ 
  resolve("helloworld");
  })
  .then(
  function(str){
  throw new Error("uhoh");
  },
  function(error){
  alert(error); 
   }
  );   

在第一段代码中,当第一个then()抛出一个异常时,它可以被第二个then()捕获并alert ‘uh oh’。这遵循了异常只能来自于上一级的规则。

在第二段代码中,回调函数和错误回调函数在同一级上,这意味着当异常在回调函数中北抛出时,它无法被捕获。事实上,第二段代码中的错误回调函数仅仅只在promise处于rejected状态或者promise本身抛出一个错误时才能被执行。

4.错误能被恢复

在一个错误回调函数中,如果你没有重新抛出错误,这个promise将会认为你已经恢复了错误并转换到了resolved状态。在下面的例子中,’I am saved’会被alert因为第一个then()中的错误回调函数并没有重新抛出异常。

var p = new Promise(function(resolve,reject){
    reject(new Error('pebkac'));
});  

p.then(
    undefined,
    function(error){ }
)
 .then(
    function(str){
        alert('I am saved!');
    },
    function(error){
     alert('Bad computer!');
    }
);   

Promise 可以被看做是洋葱的皮层。每一个then()函数都未洋葱添加了一层。每一层都代表一个奖杯处理的活动。在这层结束之后,结果会被认为已经被修复并准备经过下一层。

5.Promise可以被暂停

仅仅因为你已经在一个then()函数中执行过代码,并不意味着你不能够暂停promise去做其他事情。为了暂停当前的promise,或者要它等待另一个promise完成,只需要简单地在then()函数中返回另一个promise。

var = new Promise(/*...*/);   

p.then(function(str){
    if(!loggedIn){
        return new Promise(/*...*/);
    }
}) 
 .then(function(str){
    alert("Done!");
 });

在上面的代码中,alert不会显示一直到新的promise被解析。如果你想要将额外的依赖注入到已经存在的异步代码中,这是一中非常方便的方法。例如,你发现用户会话已经超时了因此你可能想要在继续执行后面的代码之前开始第二次登录。

6.被解析的Promise不会立即被执行

当你运行下面的代码时会alert什么内容?

function runme(){
    var i = 0;

    new Promise(function(resolve,reject){
        resolve();
    })
    .then(function(){
        i += 2;
    });

    alert(i);
}   

你可能想由于promise立即被解析了然后then()函数马上被执行(同步),因此结果结果可能是2.然而,promise需要所有的代码都异步完成。因此此时i的值依然没有改变。


本文译自six things you might not know about promises,原文地址http://www.sitepoint.com/six-things-might-know-promises/

如果你觉得本文对你有帮助,请点击为我提供赞助

评论
发表评论
3年前
赞了此文章!
WRITTEN BY
张小俊128
Intern in Baidu mobile search department。认真工作,努力钻研,期待未来更多可能。
TA的新浪微博
PUBLISHED IN
每天学点javascript

javascript进阶级教程,循序渐进掌握javascript

我的收藏