您的位置:首页 > Web前端 > JavaScript

JavaScript Promise API

2016-07-21 14:28 417 查看
尽管同步代码易于追踪和调试,但异步代码普遍在性能和灵活性上更具优势。Why "hold up the show" when you can trigger numerous requests at once and then handle them when each is ready?(这句要怎么翻??)promise和许多基于promise的新的API已经成为JavaScript世界重要的一部分。让我们来看一下promise的API如何来使用。


Promises in the Wild

XMLHttpRequest API是异步的但它并没有用Promises API,现在有一些native APIs正在使用promises:

Battery API(译者注:这篇文章我也有翻译

fetch API(XHR的取代者)

ServiceWorker API(关于这个API的文章正在路上)

promises会变得很流行,所以前端开发者们都应该去学习它。毫无疑问,Node.js是promises另一个重要的平台(显然,promises是一个核心语法特性)。

测试 promises 比你想得容易得多,因为 
setTimeout
 可以模拟你的异步“任务”


Basic Promise Usage

构造函数 
new Promise()
 应该只用于老式的异步任务,比如 
setTimeout
 或者 
XMLHttpRequest
。我们使用 
new
 关键字和promise提供的 
resolve
 和 
reject
 回调函数来创建新的
promise:
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 :( */
})


根据异步任务的返回结果,开发者可以在回调函数体的内部手动调用 
resolve
 或者 
reject
。把
XMLHttpRequest 转化为基于promise的任务就是一个实际的例子:
// 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);
});


Sometimes you don't need to complete an async tasks within the promise -- if it's possible that an async action will be taken, however, returning a promise will be best so that you can always count on a promise coming out of a given function.(译者注:求大家帮忙翻译。。)这样你就可以简单地调用
Promise.resolve()
 或者 
Promise.reject()
 而不需要使用 
new
 关键字。举例说明:
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对象,你总是可以对这个返回值使用
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被resolved时,会调用
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
 方法接收到上一个 
then
 方法的返回值。

如果一个promise已经被resolved,
then
方法有一次被调用,那么回调函数立刻执行。如果promise被rejected,而
then
方法在rejection之后,那回调函数永远不会被执行。


catch

当promise被rejected时,
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
方法里执行什么内容取决于你。一个常见的模式是发送一个
Error
catch
方法中:
reject(Error('Data could not be found'));


Promise.all

想一下JavaScript loaders:有许多个异步任务被同时触发,但你只想在它们都完成之后才做出回应---这就是
Promise.all
的由来。
Promise.all
方法传入一个promise的数组,然后在它们全部resolved之后再出发回调函数:
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!
});


你可以合并都返回promise的APIs,比如
fetch
 和 Battery API:
Promise.all([fetch('/users.json'), navigator.getBattery()]).then(function(results) {
// Both promises done!
});


当然,处理rejection是困难的。如果数组中有任意一个promise被rejected,
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(results) {
console.log('Then: ', one);
}).catch(function(err) {
console.log('Catch: ', err);
});

// From the console:
// Catch: Second!


Promise.race

Promise.race
是个有趣的方法---不是等待所有的promise被resolved或者rejected,而是只要数组中有一个promise被resolved或者rejected,
Promise.race
方法就被触发:
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!


一个很有用的例子就是在有第一资源请求和第二资源请求时可以用
Promise.race


Get Used to Promises

在过去的几年中,promise一直是一个热点话题(如果你是Dojo Toolkit用户的话,会是过去的10年间),现在promise已经从JavaScript框架特性的级别变成了JavaScript语言的特性。你将看到会有越来越多的API会基于promise来实现,这是一个很好的事情!开发者们可以避免以前的callback hell,并且异步interactions可以像其他的变量一样互相传递。promise花了很长的时间变成现在的样子,而现在是应该学习promise的时候了。

源引:https://segmentfault.com/a/1190000004476610
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JavaScript Promise