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

JavaScript Promise API

2020-08-11 05:09 393 查看

The JavaScript Promise API is awesome but can be made amazing with

async
and
await
!

JavaScript Promise API很棒,但是可以通过

async
await
变得惊人!

While synchronous code is easier to follow and debug, async is generally better for performance and flexibility. Why "hold up the show" when you can trigger numerous requests at once and then handle them when each is ready?  Promises are becoming a big part of the JavaScript world, with many new APIs being implemented with the promise philosophy. Let's take a look at promises, the API, how it's used!

尽管同步代码更易于跟踪和调试,但异步通常在性能和灵活性方面更好。 当您一次触发多个请求,然后在每个请求准备就绪时处理它们时,为什么要“暂停显示”呢? 承诺正在成为JavaScript世界的重要组成部分,许多新API都以promise理念实现。 让我们来看看Promise,API及其用法!

在野外的应许 (Promises in the Wild)

The XMLHttpRequest API is async but does not use the Promises API.  There are a few native APIs that now use promises, however:

当XMLHttpRequest API是异步,但不使用承诺API。 但是,现在有一些本机API使用Promise:

Promises will only become more prevalent so it's important that all front-end developers get used to them.  It's also worth noting that Node.js is another platform for Promises (obviously, as Promise is a core language feature).

承诺只会变得更加普遍,因此所有前端开发人员都必须习惯它们,这一点很重要。 还值得注意的是,Node.js是Promises的另一个平台(显然,Promise是核心语言功能)。

Testing promises is probably easier than you think because

setTimeout
can be used as your async "task"!

测试Promise可能比您想象的要容易,因为

setTimeout
可以用作异步“任务”!

基本承诺用法 (Basic Promise Usage)

The

new Promise()
constructor should only be used for legacy async tasks, like usage of
setTimeout
or
XMLHttpRequest
. A new Promise is created with the
new
keyword and the promise provides
resolve
and
reject
functions to the provided callback:

new Promise()
构造函数应仅用于旧式异步任务,例如
setTimeout
XMLHttpRequest
用法。 使用
new
关键字创建一个新的Promise,promise为所提供的回调提供
resolve
reject
功能:

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(result) {
/* do something with the result */
}).catch(function() {
/* error :( */
}).finally(function() {
/* executes regardless or success for failure */
});
[/code]

It's up to the developer to manually call

resolve
or
reject
within the body of the callback based on the result of their given task. A realistic example would be converting XMLHttpRequest to a promise-based task:

开发人员可以根据他们给定任务的结果,在回调函数体中手动调用“

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);
});
[/code]

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. In that case you can simply call

Promise.resolve()
or
Promise.reject()
without using the
new
keyword. For example:

有时候,你并不需要完成的承诺中异步任务-如果它可能是一个异步将采取行动,然而,返回承诺将最好的,让您可以随时在承诺未来数给定函数的出。 在这种情况下,您可以简单地调用

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);
});
}
[/code]

Since a promise is always returned, you can always use the

then
and
catch
methods on its return value!

由于总是返回承诺,因此您可以始终使用

then
catch
方法获取其返回值!

然后 (then)

All promise instances get a

then
method which allows you to react to the promise.  The first
then
method callback receives the result given to it by the
resolve()
call:

所有的Promise实例都有一个

then
方法,该方法允许您对Promise做出React。 然后,第一个
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
[/code]

The

then
callback is triggered when the promise is resolved.  You can also chain
then
method callbacks:

解决承诺后,将触发

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
[/code]

Each

then
 receives the result of the previous
then
's return value.

每个

then
接收前的结果,
then
的返回值。

If a promise has already resolved but

then
is called again, the callback immediately fires. If the promise is rejected and you call
then
after rejection, the callback is never called.

如果一个承诺已经解决,但

then
再次被调用时,回调将立即触发。 如果承诺被拒绝和你打电话
then
拒绝后,回调不会被调用。

抓住 (catch)

The

catch
callback is executed when the promise is 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!'
[/code]

What you provide to the

reject
method is up to you. A frequent pattern is sending an
Error
to the
catch
:

您提供给

reject
方法的取决于您自己。 常见的模式是将
Error
发送给
catch

reject(Error('Data could not be found'));
[/code]

最后 (finally)

The newly introduced

finally
callback is called regardless of success or failure:

无论成功与否,都会调用新引入的

finally
回调:

(new Promise((resolve, reject) => { reject("Nope"); }))
.then(() => { console.log("success") })
.catch(() => { console.log("fail") })
.finally(res => { console.log("finally") });

// >> fail
// >> finally
[/code]

Promise.all
(
Promise.all
)

Think about JavaScript loaders:  there are times when you trigger multiple async interactions but only want to respond when all of them are completed -- that's where

Promise.all
comes in.  The
Promise.all
method takes an array of promises and fires one callback once they are all resolved:

想想JavaScript加载程序:有时候您会触发多个异步交互,但只想在所有异步交互完成后才进行响应-这就是

Promise.all
进入的地方
Promise.all
方法采用一组promises并触发一次回调他们都解决了:

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

A perfect way of thinking about

Promise.all
is firing off multiple AJAX (via
fetch
) requests at one time:

考虑

Promise.all
一种完美方法是一次触发多个AJAX(通过
fetch
)请求:

var request1 = fetch('/users.json');
var request2 = fetch('/articles.json');

Promise.all([request1, request2]).then(function(results) {
// Both promises done!
});
[/code]

You could combine APIs like

fetch
and the Battery API since they both return promises:

您可以结合使用

fetch
和Battery API之类的API,因为它们都返回承诺:

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

Dealing with rejection is, of course, hard. If any promise is rejected the

catch
fires for the first rejection:

当然,处理拒绝是很难的。 如果任何承诺被拒绝,则第一个拒绝的

catch
触发:

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: ', results);
}).catch(function(err) {
console.log('Catch: ', err);
});

// From the console:
// Catch: Second!
[/code]

Promise.all
will be super useful as more APIs move toward promises.

随着越来越多的API向

Promise.all
将超级有用。

Promise.race
(
Promise.race
)

Promise.race
is an interesting function -- instead of waiting for all promises to be resolved or rejected,
Promise.race
triggers as soon as any promise in the array is resolved or rejected:

Promise.race
是一个有趣的功能
Promise.race
无需等待所有诺言被解决或拒绝,
Promise.race
在阵列中的任何诺言被解决或拒绝时
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!
[/code]

A use case could be triggering a request to a primary source and a secondary source (in case the primary or secondary are unavailable).

用例可能会触发对主要来源和次要来源的请求(如果主要来源或次要来源不可用)。

习惯承诺 (Get Used to Promises)

Promises have been a hot topic for the past few years (or the last 10 years if you were a Dojo Toolkit user) and they've gone from a JavaScript framework pattern to a language staple.  It's probably wise to assume you'll be seeing most new JavaScript APIs being implemented with a promise-based pattern...

在过去的几年中(或者,如果您是Dojo Toolkit用户,则是过去的十年),承诺一直是一个热门话题,并且它们已经从JavaScript框架模式变成了语言的主要内容。 假设您将看到大多数新JavaScript API正在使用基于承诺的模式来实现,这可能是明智的……

...and that's a great thing!  Developers are able to avoid callback hell and async interactions can be passed around like any other variable.  Promises take some time getting used to be the tools are (natively) there and now is the time to learn them!

...那真是太好了! 开发人员可以避免回调地狱,并且可以像其他任何变量一样传递异步交互。 承诺要花一些时间才能习惯这些工具(本地),现在是时候学习它们了!

翻译自: https://davidwalsh.name/promises

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: