本文转载自:众成翻译
译者:iOSDevLog
链接:http://www.zcfy.cc/article/3814
原文:https://www.fullstackreact.com/30-days-of-react/day-15/
今天,我们将要看看我们需要知道什么来从高层次了解Promises,所以我们可以使用这个非常有用的概念构建我们的应用。
昨天我们将 fetch
库安装到我们的 create-react-app
项目 我们开始 第12天. 今天,我们将拿起从昨天讨论的概念和Promises的 艺术 .
Promise
正如 mozilla 所定义的,承诺
对象用于处理异步计算,其中有一些重要的保证难以用回调方法处理 (更老式的处理异步代码的方法)。
Promise
对象只是围绕一个值的包装,它在实例化对象时可能也可能不知道,并提供了一个已知的 (也称为 resolved
) 或由于失败原因而不可用 (我们将此称为rejected
) 后 处理该值的方法 。
使用 "承诺" 对象使我们有机会将异步操作的最终成功或失败关联到功能 (无论出于何种原因)。它还允许我们使用类似于同步的代码来处理这些复杂的场景。
例如,考虑下面的同步代码,我们在 javascript 控制台中打印出当前时间:
var currentTime = new Date(); console.log('The current time is: ' + currentTime);
这是相当直接的,并作为 new Date()
对象表示浏览器知道的时间。现在考虑我们在其他远程机器上使用不同的时钟。例如,如果我们正在做一个快乐的新年时钟,这将是伟大的,能够同步用户的浏览器与其他人使用一个单一的时间值为每个人,所以没有人错过的落球仪式。。
假设我们有一个方法来处理从远程服务器获取当前时间的 getCurrentTime()
时钟。现在,我们将用setTimeout()
来表示这一点,它返回时间 (就像对慢速 api 发出请求一样):
function getCurrentTime() { // Get the current 'global' time from an API return setTimeout(function() { return new Date(); },2000); } var currentTime = getCurrentTime() console.log('The current time is: ' + currentTime);
我们的console.log()
日志值将返回超时处理程序 id,这绝对 不是 当前时间。传统上,我们可以使用回调来更新代码,以便在可用时间时调用:
function getCurrentTime(callback) { // Get the current 'global' time from an API return setTimeout(function() { var currentTime = new Date(); callback(currentTime); },2000); } getCurrentTime(function(currentTime) { console.log('The current time is: ' + currentTime); });
function getCurrentTime(onSuccess,onFail) { // Get the current 'global' time from an API return setTimeout(function() { // randomly decide if the date is retrieved or not var didSucceed = Math.random() >= 0.5; if (didSucceed) { var currentTime = new Date(); onSuccess(currentTime); } else { onFail('Unknown error'); } },2000); } getCurrentTime(function(currentTime) { console.log('The current time is: ' + currentTime); },function(error) { console.log('There was an error fetching the time'); });
现在,如果我们想根据第一个请求的值提出请求怎么办?作为一个简短的示例,让我们再次重用 getCurrentTime()
函数 (就好像它是第二个方法,但允许我们避免添加另一个复杂的函数):
function getCurrentTime(onSuccess,onFail) { // Get the current 'global' time from an API return setTimeout(function() { // randomly decide if the date is retrieved or not var didSucceed = Math.random() >= 0.5; console.log(didSucceed); if (didSucceed) { var currentTime = new Date(); onSuccess(currentTime); } else { onFail('Unknown error'); } },2000); } getCurrentTime(function(currentTime) { getCurrentTime(function(newCurrentTime) { console.log('The real current time is: ' + currentTime); },function(nestedError) { console.log('There was an error fetching the second time'); }) },function(error) { console.log('There was an error fetching the time'); });
以这种方式处理 异步 会很快变得复杂。此外,我们可以从以前的函数调用中获取值,如果我们只想得到一个... 在处理应用启动时还没有的值时,有很多棘手的情况需要处理。
进入Promise
使用承诺,另一方面帮助我们避免了很多这种复杂性 (虽然不是一个银弹解决方案,参考《人月神话》)。以前的代码,这可以被称为意大利面条代码可以变成一个更整洁,更同步的前瞻版本:
function getCurrentTime(onSuccess,onFail) { // Get the current 'global' time from an API using Promise return new Promise((resolve,reject) => { setTimeout(function() { var didSucceed = Math.random() >= 0.5; didSucceed ? resolve(new Date()) : reject('Error'); },2000); }) } getCurrentTime() .then(currentTime => getCurrentTime()) .then(currentTime => { console.log('The current time is: ' + currentTime); return true; }) .catch(err => console.log('There was an error:' + err))
以前的源代码示例对正在发生的事情进行了一些清理和清除,避免了许多棘手的错误处理/捕获。
为了获得成功的值,我们将使用Promise
实例对象上的 then()
功能。then()
函数被调用,无论返回值是Promise
本身。例如,在上面的示例中,getCurrentTime()
函数解析为currentTime()
值 (在成功完成时),并在返回值 (这是另一个承诺) 上调用then()
函数,依此类推等等。
要捕获在承诺链中任何地方发生的错误,我们可以使用catch()
方法。
我们在上面的例子中使用一个承诺链,以创建一个 链 的行动,被称为一个接一个。
承诺链听起来很复杂,但基本上很简单。实质上,我们可以连续地 "同步" 调用多个异步操作。对then()
的每次调用都用以前的then()
函数的返回值来调用。
例如,如果我们想操纵getCurrentTime()
调用的值,我们可以在链中添加一个链接,如下所示:getCurrentTime() .then(currentTime => getCurrentTime()) .then(currentTime => { return 'It is now: ' + currentTime; }) // this logs: "It is now: [current time]" .then(currentTimeMessage => console.log(currentTimeMessage)) .catch(err => console.log('There was an error:' + err))
单使用Guarantee
承诺在任何特定的时间都只应该在三种状态之一:
一个 待定 的承诺只能导致一个满足状态或一个被拒绝的状态 一次且仅一次,这可以避免一些相当复杂的错误场景。这意味着,我们只能返回一个承诺一次。如果我们想重新运行一个使用承诺的函数,我们需要创建一个 新 的。
创建一个Promise
我们可以使用 Promise
构造函数来创建新的承诺 (如上面的示例所示)。它接受一个有两个参数来运行的函数:
从上面回顾我们的函数,我们可以看到,如果请求成功,我们调用 resolve()
函数,如果该方法返回错误条件,则调用 reject()
函数。
var promise = new Promise(function(resolve,reject) { // call resolve if the method succeeds resolve(true); }) promise.then(bool => console.log('Bool is true'))
现在我们知道了什么是承诺,如何使用,以及如何创建它们,我们实际上可以使用昨天安装的 fetch()
库。