如何在你的应用中实现 ES6 Promises
介绍
Promises 是 ES6 中新增的一个非常重要的功能。Promises 的引入有助于简化异步编程,使代码更易于理解,同时消除了与回调相关的问题。
在本指南中,我们将了解这些 ES6 承诺是什么以及如何在我们的应用程序中使用它们。在应用程序中使用承诺的最常见示例之一是发出数据库请求或 API 调用,并且您必须在收到数据库的响应后更新 UI 上的某些 DOM 元素。
什么是承诺?
让我们从 Promise 的基本定义开始。Promise 是一个对象,可以用作延迟计算的最终结果的占位符。因此,可以说它是未来值的容器。
这就是您需要记住的有关 Promises 的定义的全部内容。
创建新的承诺
要在我们的应用程序中创建一个新的 Promise,我们必须使用 Promise 构造函数。
const myNewPromise = new Promise((resolve, reject) => {
if (Math.random() * 100 == 100) {
resolve('Wow, You hit a century!');
}
reject(new Error('Oops, You missed hitting century !'));
});
如果你看一下上面的代码,你会发现我们并没有真正编写要在此函数中执行的实际代码(例如,一旦承诺得到解决,就会更新页面上的 UI)。相反,我们以更精简的方式处理这个问题。
我们要做的是利用传递给 Promise 的“resolve”参数。此外,此参数实际上是一个函数,我们可以将参数传回 resolve。此返回值将表示一旦解析完成,我们想要从 promise 中传回的内容。
使用 Promises
要使用上面创建的 Promise,我们可以使用 then() 方法。then() 方法接受两个参数/回调。- 当我们的 Promise 得到解决时,将调用第一个回调(例如,这可能是 AJAX 调用完成并且我们从后端收到一些响应时)。当我们的 Promise 被拒绝时,将调用第二个回调(例如,我们的 AJAX 调用由于网络连接问题而失败)。
所以我们可以简单地使用:
myNewPromise.then((resolvedValue) => {
console.log(resolvedValue); // Logs 'Wow, You hit a century!'
}, (errorValue) => {
console.log(errorValue); // Logs 'Oops, You missed hitting century !'
});
还有一种编写此代码的简便方法:
const onResolved = (resolvedValue) => console.log(resolvedValue);
const onRejected = (errorValue) => console.log(errorValue);
myPromise.then(onResolved, onRejected);
错误/异常处理
理想情况下,我们应该使用 catch() 来处理错误,而不是使用 promise.then(resolveFn, rejectionFn)。
此外,与使用拒绝函数相比,catch() 是一种更明确的错误处理方法。当我们想要链接承诺时,我们可以在链的末尾使用一个 catch() 来处理可能由我们的初始承诺或任何处理程序引起的任何异常。
下面是使用 catch() 的示例
var promise1 = new Promise((resolve, reject) => {
if (true) {
throw new Error("Rejected!"); // same as rejected
} else {
resolve(100);
}
});
// trailing .catch() handles rejection
promise1.then((val) => console.log("Successful!"))
.then((val) => console.log("Returned value is : ", val))
.catch((error) => console.log("error: ", error.message));
// error: Rejected!
编写承诺
当处理多个承诺时,我们可能会遇到一种情况,即我们希望在所有承诺完成后开始处理。例如,假设我们有一个基于用户偏好的动态列和这些列的动态数据。因此,我们将有两个 API 调用 - 一个用于获取这些动态列,另一个用于使用实际数据。因此,只有当我们从服务器获得这两个 API 调用的响应时,我们才能够将网格数据/主体映射到这些列。
这就是 Promise.all 可以提供帮助的地方。它需要一个 Promise 数组,只有当所有 Promise 都成功后,它们才会解析,以编写上述场景。
相反,我们可以用以下方式处理它:
var getJSONFromServer = function(url) {
return new Promise((resolve, reject) => {
$.getJSON(url)
.done((json) => resolve(json))
.fail((xhr, status, err) => reject(status + err.message));
});
}
var gridUrls = {
'http://www.someapi.com/getGridColumns',
'http://www.someapi.com/getGridData'
},
itemPromises = gridUrls.map(getJSONFromServer);
Promise.all(itemPromises)
.then(function(results) {
// We reach here only if ALL promises are successful
results.forEach(function(item) {
// Render the grid
});
})
.catch(function(error) {
// Catch failure of first failed promise
console.log("Failed: ", error);
});
使用 Promises.all(),传递给 Promise.all() 的任何承诺中的任何异常都将导致 Promise 被拒绝。
在某些情况下,我们不需要等待数组中的所有 Promise,但我们希望从数组中的第一个 Promise 获得响应以成功。为此,我们可以使用 Promise.race()。这也会采用一个 Promise 数组,但与 Promise.all() 不同,race() 会在数组中的第一个 Promise 实现后立即实现。
Promise.all() 具有所谓的快速失败行为。这意味着,如果传递的 Promise 数组中的任何 Promise 被拒绝,Promise.all() 产生的 Promise 将被立即拒绝。因此,它实际上不会等待其他 Promise 完成,我们只会收到被拒绝请求的错误。
Promise.all 示例
下面是另一个使用 Promise.all 的例子。通过输出日志,你可以清楚地看到每个 Promise 的执行顺序。
function DoThisAsyncTask(delayParam) {
return new Promise(function(resolve) {
setTimeout(function() {
console.log('Resolving promise with delay : ', delayParam);
resolve('Done ' + delayParam);
}, delayParam);
});
}
var promise = Promise.all([DoThisAsyncTask(1500), DoThisAsyncTask(2500), DoThisAsyncTask(500), DoThisAsyncTask(3500)]);
promise.then(function(data) {
console.log('All promises resolved!');
data.forEach(function(text) {
console.log(text);
});
});
//Output
//Resolving promise with delay : 500
//Resolving promise with delay : 1500
//Resolving promise with delay : 2500
//Resolving promise with delay : 3500
//All promises resolved!
//Done 1500
//Done 2500
//Done 500
//Done 3500
承诺状态
在任何给定时间,Promise 始终处于以下三种互斥状态之一:
- 在结果可用之前,Promise 被称为待定的(例如等待服务器以 JSON 响应回复)。
- 如果结果可用,则称 Promise 已实现(例如服务器向浏览器发出响应)。
- 如果发生任何错误/异常,则 Promise 被拒绝(例如,由于网络连接问题导致 AJAX 调用失败)。
仅当所有事情都完成(即成功或被拒绝)时,承诺才会得到解决。
一个 Promise 仅需解决一次。
结论
添加对 Promises 的原生支持是 ES6 的一个非常好的补充。这对于实现大量异步功能的应用程序非常有用。与使用回调处理程序相比,它提高了代码的可读性。此外,使用 Promises,实现错误处理要容易得多。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~