当前位置: 首页 > 科技观察

使用Promises编写更好的JavaScript代码

时间:2023-03-20 10:34:04 科技观察

您可能已经听说Promises是未来。所有酷孩子都使用它们,但您不知道它们为什么如此特别。你不能使用回调吗?有什么大不了的?在本文中,我们将了解什么是承诺以及如何使用它们来编写更好的JavaScript。Promises易于阅读假设我们想从HipsterJesus的API获取一些数据并将该数据添加到我们的页面。这些API的响应数据形式如下:{"text":"

Loremipsum...

","params":{"paras":4,"type":"hipster-latin"}}在使用回调的时候,我们通常会这样写一些东西:$.getJSON('http://hipsterjesus.com/api/',function(data){$('body').append(data.text);});如果您有使用jQuery的经验,您会认识到我们创建了一个GET请求并期望响应是JSON。我们还传递了一个回调函数,该函数接受响应的JSON以将数据添加到文档中。另一种写法是使用getJSON方法返回的promise对象。您可以直接在此返回的对象上绑定回调。varpromise=$.getJSON('http://hipsterjesus.com/api/');promise.done(函数(数据){$('body').append(data.text);});在上面的回调例子中,它在响应成功时将API请求的结果添加到文档中。但是当响应失败时会发生什么?我们可以将失败处理程序绑定到我们的承诺。varpromise=$.getJSON('http://hipsterjesus.com/api/');promise.done(函数(数据){$('body').append(data.text);});promise.fail(function(){$('body').append('

Ohno,somethingwentwrong!

');});大部分人删除了promise变量,这样更简洁,代码作用一目了然。$.getJSON('http://hipsterjesus.com/api/').done(函数(数据){$('body').append(data.text);}).fail(函数(){$('body').append('

Ohno,somethingwentwrong!

');});jQuery还包括一个永远在线的事件处理程序,无论请求成功还是失败,它都会被调用。$.getJSON('http://hipsterjesus.com/api/').done(函数(数据){$('body').append(data.text);}).fail(函数(){$('body').append('

哦不,出了点问题!

');}).always(function(){$('body').append('

我保证会一直添加!.

');});通过使用承诺,回调的顺序符合预期。我们可以确保先调用正常回调,然后调用失败回调,最后调用一直发生的回调。更好的API假设我们要为HipsterJesusAPI创建一个包装器对象。我们将添加一个方法html,它将从API返回HTML数据。我们可以让方法返回一个承诺,而不是设置回调处理程序来解决请求。varhipsterJesus={html:function(){return$.getJSON('http://hipsterjesus.com/api/').then(function(data){returndata.text;});}};这很酷,这样我们就可以绕过promise对象,而不必担心它的值何时或如何被解析。任何需要promise返回值的代码只需注册一个成功响应回调。then方法允许我们修改承诺的结果并将其传递给链中的下一个处理程序。这意味着现在我们可以像这样使用新的API:hipsterJesus.html().done(function(html){$("body").append(html);});直到最近,AngularJS才有了一个杀手级的特性,Templates可以直接绑定到promises。在Angular控制器中,像这样:$scope.hipsterIpsum=$http.get('http://hipsterjesus.com/api/');这样,在template中写上{{hipsterIpsum.text}}就很简单了。Angular不需要在promise解析时自动更新视图。不幸的是,Angular团队放弃了这个功能。现在,可以通过调用$parseProvider.unwrapPromises(true)来启用它。我希望Angular和其他框架将始终包含此功能(我会密切关注它)。链接承诺最酷的部分是您可以将它们链接在一起。假设我们要向返回数组的API添加方法。varhipsterJesus={html:function(){return$.getJSON('http://hipsterjesus.com/api/').then(function(data){returndata.text;});},段落:function(){returnthis.html().then(function(html){returnhtml.replace(/<[^>]+>/g,"").split("");});}};我们在上面的方法中使用了一个HTML方法,我们在paragraphs方法中使用了该方法。因为promise回调函数的返回值将传递给链中的下一个回调,所以我们可以自由地创建小的、函数式的方法来改变传递的数据。我们可以根据需要多次链接承诺。让我们添加一个。varhipsterJesus={html:function(){return$.getJSON('http://hipsterjesus.com/api/').then(function(data){returndata.text;});},段落:function(){returnthis.html().then(function(html){returnhtml.replace(/<[^>]+>/g,"").split("");});},sentences:function(){returnthis.paragraphs().then(function(paragraphs){return[].concat.apply([],paragraphs.map(function(paragraph){returnparagraph.split(/./);}));});}};多次调用Promises最显着的特征可能是调用多个API的能力。使用回调时,如果需要同时进行两个API调用会怎样?你可能会这样写:varfirstData=null;varsecondData=null;varresponseCallback=function(){if(!firstData||!secondData)return;//dosomething}$.get("http://example.com/first",function(data){firstData=data;responseCallback();});$.get("http://example.com/second",function(data){secondData=data;responseCallback();});使用承诺,这就简单多了:varfirstPromise=$.get("http://example.com/first");varsecondPromise=$.get("http://example.com/second");$.when(firstPromise,secondPromise).done(function(firstData,secondData){//dosomething});在这里,我们使用when方法并将其绑定到将在两个请求完成时调用的处理程序。结论这是承诺。希望您立即想到可以用promise做的一些可怕的事情。您最喜欢使用它们的方式是什么?在评论中让我知道!*注:为简单起见,本文使用jQuery的延迟执行。jQuery的Deferred对象和更标准的Promises/A+规范之间存在细微差别。有关详细信息,请参阅jQuerywiki上的问答。英文原文:WriteBetterJavaScriptwithPromises翻译链接:http://www.oschina.net/translate/write-javascript-promises