JavaScript Promise API

同步编程一般来讲易于调试和维护,然而,异步编程一般能得到更好的性能和更大的灵活性。异步的最大特色是无需等待。“Promises”渐渐成为JavaScript里最重要的一部分,大量的新API都开始promise原理实现。下面让咱们看一下什么是promise,以及它的API和用法!javascript

Promises现状

XMLHttpRequest API是异步的,但它没有使用promise API。但有不少原生的 javascript API 使用了promise:html

Promises未来只会变得愈来愈流行、广泛,很是重要,全部的前端开发人员都将用到它。另外一个值得注意的是,Node.js是基于Promises的平台(很显然,Promise是它的一个核心特征)。前端

Promises的用法比你想象的要简单——若是你之前喜欢使用setTimeout来控制异步任务的话!html5

Promise基本用法

new Promise()构造器能够用在传统的异步任务中,就像之前 setTimeoutXMLHttpRequest 的用法同样。一个新的 Promise 使用 new 关键字生成,同时,这个 Promises 提供了 resolvereject 函数让咱们执行回调操做:java

var p = new Promise(function(resolve, reject) { // Do an async task async task and then... if(/* good condition */) { resolve('Success!'); } else { reject('Failure!'); } }); p.then(function() { /* do something with the result */ }).catch(function() { /* error 🙁 */ }) 

程序员能够手动的在回调函数内部根据执行状况调用 resolvereject 函数。下面是一个比较具备现实意义的例子,它将一个 XMLHttpRequest 调用转换为 基于 Promises 的任务:程序员

// From Jake Archibald's Promises and Back:
// http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest function get(url) { // Return a new promise. return new Promise(function(resolve, reject) { // Do the usual XHR stuff var req = new XMLHttpRequest(); req.open('GET', url); req.onload = function() { // This is called even on 404 etc // so check the status if (req.status == 200) { // Resolve the promise with the response text resolve(req.response); } else { // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error(req.statusText)); } }; // Handle network errors req.onerror = function() { reject(Error("Network Error")); }; // Make the request req.send(); }); } // Use it! get('story.json').then(function(response) { console.log("Success!", response); }, function(error) { console.error("Failed!", error); }); 

Promise.resolve()Promise.reject() 能够直接被调用。有时候,当判断出 promise 并不须要真正执行时,咱们并不须要 使用 new 建立 Promise 对象,而是能够直接调用 Promise.resolve()Promise.reject()。好比:es6

var userCache = {}; function getUserDetail(username) { // In both cases, cached or not, a promise will be returned if (userCache[username]) { // Return a promise without the "new" keyword return Promise.resolve(userCache[username]); } // Use the fetch API to get the information // fetch returns a promise return fetch('users/' + username + '.json') .then(function(result) { userCache[username] = result; return result; }) .catch(function() { throw new Error('Could not find user: ' + username); }); } 

由于 promise 确定会返回,因此,咱们能够使用 thencatch 方法处理返回值!web

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 

then 回调动做的触发时机是 promise 被执行完。咱们还能够串联 then 方法执行回调操做:json

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 调用都会以以前的 then 调用的返回值为参数。

若是一个 promise 已经执行完成,单 then 被再次调用时,回调动做将会被再次执行。而若是这个 promise 里执行的是reject 回调函数,这是再调用 then 方法,回调函数将不会被执行。

catch

catch 当一个 promise 被拒绝(reject)时,catch 方法会被执行:

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 方法里处理执行失败的结果,而在catch 里执行异常结果:

reject(Error('Data could not be found')); 

Promise.all

在咱们的异步调用时常常有这样一种场景:咱们须要同时调用多个异步操做,但但愿只有等全部的操做都完成后,咱们才去执行响应操做——这就是 Promise.all 的做用。 Promise.all 方法能够接收多个 promise 做为参数,以数组的形式,当这些 promise 都成功执行完成后才调用回调函数。

Promise.all([promise1, promise2]).then(function(results) { // Both promises resolved }) .catch(function(error) { // One or more promises was rejected }); 

一个很好的能演示 Promise.all 用法的例子是,执行多个 AJAX 操做(经过 fetch) 调用:

var request1 = fetch('/users.json'); var request2 = fetch('/articles.json'); Promise.all([request1, request2]).then(function(results) { // Both promises done! }); 

咱们还可将fetch电池状态API混合一块儿执行,由于它们返回的都是 promise:

Promise.all([fetch('/users.json'), navigator.getBattery()]).then(function(results) { // Both promises done! }); 

一旦 promise 里调用了reject函数,也就是执行被拒绝了,没有可以正常完成,状况会有些复杂。一旦 promise 被拒绝,catch 方法会捕捉到首个被执行的reject函数:

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(results) { console.log('Then: ', one); }).catch(function(err) { console.log('Catch: ', err); }); // From the console: // Catch: Second! 

Promise.all 是很是重要的接口,将会在不少新诞生的 promise API中扮演重要的做用。

Promise.race

Promise.race 是一个有趣的函数——它不是等待全部的 promise 被resolvereject,而是在全部的 promise 中只要有一个执行结束,它就会触发:

var req1 = new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { resolve('First!'); }, 8000); }); var req2 = new Promise(function(resolve, reject) { // A mock async action using setTimeout 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在过去几年是一个很是火爆的话题,它甚至从JavaScript里抽离出来变成了一个语言架构。相信很快咱们将见到有越来越多的JavaScript API将使用以promise为基础的模式。

《本文转自:http://www.webhek.com/javascript-promise-api》

相关文章
相关标签/搜索