只管同步代码易于追踪和调试,但异步代码广泛在机能和灵活性上更具上风。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的时刻了。