版权声明:此文章转载自极客头条
如需转载请联系听云College团队成员小尹 邮箱:yinhy#tingyun.com
尽管同步代码很容易跟踪调试,异步代码在性能和灵活性上更胜一筹。如果你能立刻触发多个请求并在它们各自准备好之后处理,那岂不是很棒。Promises实现了很多蕴含Promise哲学的API,其正在成为JavaScript世界中的重要成员。让我们看一看Promises,它的API以及如果使用。
Promises
XMLHttpRequest API是异步的,但没有使用Promises API。然而,这里有一些目前使用Promises的原生APIs。:
Battery API
fetch API (XHR's 的替代品)
ServiceWorker API (很快就会公布)
romises趋于流行,所以每个前端开发者熟悉它很重要。很有必要知道Node.js是Promises的另一个平台(显然Promise是语言核心特性)
测试Promises比你想的还简单,因为setTimeout可以被当做你的异步任务。
Promise基础用法
使用new关键字创建一个Promise,Promise提供resolve和reject函数用于回调:
var p = new Promise(function(resolve, reject) { // Do some processing if(/* good condition */) { resolve('Success!'); } else { reject('Failure!'); } });
基于开发者执行的任务结果,由他们手动的回调resolve或reject函数。同时注意你在处理异步方法时,不必总是在promise内完全实现异步任务,使用promise的优势在于你可以指望promise指定的函数。举个例子:
var userCache = {}; // There's a chance an async action may take place // i.e. if the user isn't in cache, use fetch to get their info // This is a perfect function to return a promise from function getUserDetail(username) { return new Promise(function(resolve, reject) { // Not async but since we're in a promise we can resolve ourself if(userCache[username]) { resolve(userCache[username]); } else { // Use the fetch API to get the information fetch('users/' + username + '.json') .then(function(result) { userCache[username] = result; resolve(result); }) .catch(function() { reject(Error('Could not find user: ' + username)); }); } }); } // Use the promise getUserDetail('davidwalsh') .then(function(userInfo) { // Do something with the user info }) .catch(function(err) { // Do something with the error });
因为总是返回一个promise,所以你可以对返回值使用then和catch方法。
then方法
所有promise实例有then方法允许你对promise响应。第一个then方法接收resolve方法调用的结果。
new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { resolve(10); }, 3000); }) .then(function(result) { console.log(result); }); // From the console: // 10
promise调用resolve方法后触发then方法。你也可以链式调用then方法。
new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { resolve(10); }, 3000); }) .then(function(num) { console.log('first then: ', num); return num * 2; }) .then(function(num) { console.log('second then: ', num); return num * 2; }) .then(function(num) { console.log('last then: ', num);}); // From the console: // first then: 10 // second then: 20 // last then: 40
每个then方法接收前一个的返回值。
catch方法
catch在promise执行reject方法之后执行。
new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { reject('Done!'); }, 3000); }) .then(function(e) { console.log('done', e); }) .catch(function(e) { console.log('catch: ', e); }); // From the console: // 'catch: Done!'
reject方法由你实现。大多时候发送Error到catch
reject(Error('Data could not be found'));
Promise.all方法
想一下JavaScript加载:某时触发了很多异步的交互,但你想等它们全部完成再进行响应 -- 这就需要Promise.all函数了。Promise.all函数操作一个promise列表,在所有promise处理完后执行一个回调。
Promise.all([promise1, promise2]).then(function(result1, result2) { // Both promises resolved }) .catch(function(error) { // One or more promises was rejected });
一个思考Promise.all的好方式就是同时发送多个AJAX请求:
var request1 = fetch('/users.json'); var request2 = fetch('/articles.json'); Promise.all([request1, request2]).then(function(response1, response2) { // Both promises done! });
你可以组合使用fetch方法和Battery API,因为他们都返回promise:
var request2 = fetch('/articles.json'); Promise.all([fetch('/users.json'), navigator.getBattery()]).then(function(response, battery) { // Both promises done! });
处理一个rejection是很困难的。如果promise中有任何一个reject,catch方法会处理第一个rejection。
var req1 = new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { resolve('First!'); }, 4000); }); var req2 = new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { reject('Second!'); }, 3000); }); Promise.all([req1, req2]).then(function(one, two) { console.log('Then: ', one); }).catch(function(err) { console.log('Catch: ', err); }); // From the console: // Then: Second!
当API趋向promise时,Promise.all会更加有用。
Promise.race方法
Promise.race是个很有趣的函数 -- 和等待所有promise处理完不同,Promise.race在promise列表中任意一个promise处理完就立刻被调用:
var req1 = new Promise(function(resolve, reject) { setTimeout(function() { resolve('First!'); }, 8000); }); var req2 = new Promise(function(resolve, reject) { setTimeout(function() { resolve('Second!'); }, 3000); }); Promise.race([req1, req2]).then(function(one) { console.log('Then: ', one); }).catch(function(one, two) { console.log('Catch: ', one); }); // From the console: // Then: Second!
一个用例是绑定主要资源请求和备份资源请求(防止主要或备份不可用)
习惯Promises
Promises是过去几年(如果你是Dojo Toolkit用户,那么十年)的热门话题,它从JavaScript框架模式演变成语言产品。你很可能将会看到很多新的JavaScript APIs用promise模式实现...
...这是一件很棒的事!开发者可以绕开回调地狱,异步交互可以像其他变量一样分发。Promises作为一种工具需要一段时间去适应,是时候开始学习它了!