2014-05-21 60 views
2

我对JavaScript进行了相当的代码编写,虽然我认为我确实了解承诺的工作原理,但我不确定是否完全理解承诺为JS世界带来的优势。考虑下面的代码,简单地说带有包含更多调用的回调的异步调用等等。了解JavaScript中的承诺

(function doWorkOldSchool() { 

    setTimeout(function() { 

     // once done resolve promise 

     console.log("work done"); 

     setTimeout(function goHome() { 

      // once done resolve promise 

      console.log("got home"); 

      try { 

       setTimeout(function cookDinner() { 

        // this exception will not be caught 

        throw "No ingredients for dinner!"; 
        console.log("dinner cooked"); 

        setTimeout(function goToSleep() { 

         // once done resolve promise 

         console.log("go to sleep"); 

        }, 2000); 

       }, 2000); 

      } catch (ex) { 
       console.log(ex); 
      } 

     }, 2000); 

    }, 2000); 

}()); 

一个问题,我这个看:

  1. 例外回调的内部抛出是无用的。是否正确地说,当抛出调用发生时,这些抛出调用超出了范围,因此这个异常不能被调用并且一直到达顶部?这种例外如何处理?

  2. 第二个问题我发现这个嵌套业务可能会非常深入,即使您可以在setTimeout代码之外保留回调函数代码,它可能会变得一团糟。

因此,有人可以先澄清一下,如果还有什么其他问题或者这种编码的优势是明显的吗?现在

,下面我编写的程序,做同样的事情真的,但使用的承诺这一次:

function doWork() { 

    return new Promise(function(res, rej) { 

     // do your asynchronous stuff 

     setTimeout(function() { 

      // once done resolve promise 

      res("work done"); 

     }, 2000); 

    }); 
} 


function goHome(succ) { 

    console.log(succ); 

    return new Promise(function(res, rej) { 

     // do your asynchronous stuff 

     setTimeout(function() { 

      // once done resolve promise 

      res("got home"); 

     }, 2000); 

    }); 
} 


function cookDinner(succ) { 

    console.log(succ); 

    //if exception thrown here it will be caught by chained err handler 
    throw "No ingredients for dinner Exception!"; 

    return new Promise(function(res, rej) { 

     // do your asynchronous stuff 

     setTimeout(function() { 

      // something went wrong so instead of using throw we reject the promise 

      rej("No ingredients for dinner!"); 

      // once done resolve promise 

     }, 2000); 

    }); 
} 


function goToSleep(succ) { 

    console.log(succ); 

    return new Promise(function(res, rej) { 

     // do your asynchronous stuff 

     setTimeout(function() { 

      // once done resolve promise 

      res("zzz... zz.."); 

     }, 2000); 

    }); 
} 


doWork() 
    .then(goHome) 
    .then(cookDinner) 
    .then(goToSleep) 
    .then(function(succ) { 

     console.log(succ); 

    }, function(err) { 
     console.log(err); 
    }); 

以前的解决方案相比我看不出有什么明显的问题,通过这种方法,除了你显然必须理解承诺编码/维护这件事。然而,其优点是:

  1. 抛出的异常内部处理程序将被捕获到进一步链接到某处的err处理程序中。

  2. 被拒绝的承诺将通过链接ERR处理器

  3. 的代码捕获,是更清洁

现在,我的理解是否正确,或是否有每种方法的任何其他优势/劣势?

+0

是的。是。是。我不会担心后续的维护工作......承诺是ES6草案的一部分,并且有据可查。额外冗长的代价远远高于顶级代码的可读性。 – spender

回答

-1

承诺一次只能返回/决定一个值,所以一旦选择了一个值,它就不能被更改。因此,如果用户点击一个div一旦承诺只执行一次
例:

p = new Promise(function (res, rej) { 
var b = document.getElementById('helloWorld'); 
    b.onclick = function() { 
    res(prompt('value')); 
    }; 
}); 
p.then(function(val) { console.log(val); }); 

总会有只有一个值,该值将在日志中。 这对于游戏/应用程序的GUI和控件很有用。 你也可以在Promise中有两个事件监听器,这对加载图像和文件很有用。即使在添加成功或失败处理程序后,Promise也会作出反应,因此您创建了一个成功函数,尽管稍后会创建失败函数,但如果失败,常规事件处理程序会生成错误,但Promises不会在稍后调用该函数它被创建。这使您可以更专注于如何对事件做出反应,而不必担心事物的时间安排。加载事物非常有用。
Amazing Page On Promises

0

您的代码使用了一些反模式,您不应该创建承诺(例如,通过new Promise,“延期”等)在应用程序代码。你也不能混合使用回调和承诺,因为这样你就失去了异常冒泡(承诺的要点)并且让你的代码超级冗长。

您可以使用图书馆或实现自己的延迟:

function delay(ms, val) { 
    return new Promise(function(res){setTimeout(res.bind(null, val), ms);}); 
} 

然后:

function doWork() { 
    return delay(2000, "work done"); 
} 

doWork() 
    .then(function(succ) { 
     console.log(succ); 
     return delay(2000, "got home"); 
    }) 
    .then(function(succ) { 
     console.log(succ); 
     // Never throw strings, yet another anti-pattern 
     throw new Error("No ingredients for dinner Exception!"); 
     // Pointless to add code after throw 
    }) 
    .then(function(succ) { 
     return delay(2000, "zzz.. zz.."); 
    }) 
    // Don't use the second argument of .then, use .catch 
    .catch(function(err) { 
     console.log("error: ", err); 
    }); 

为何要用.catch,而不是第二个参数?那么,比较你会如何写同步:

try { 
    doWork(); 
    console.log("work done"); 
    sleep(2000); 
    console.log("got home"); 
    sleep(2000); 
    throw new Error("No ingredients for dinner Exception!";) 
    sleep(2000); 
    console.log("zzz.. zz.."); 
} 
catch(e) { 
    console.log("error: ", err); 
} 

得到它?

+0

我不确定我是否理解了你的第一段,你能否详细说明或指出URL的解释? – spirytus

+0

@spirytus如果你看看我的代码并将它与你的代码进行比较,是不是可以解释它? :P – Esailija