Through its popularity and recent improvements, JavaScript is increasingly becoming a web programmer’s best friend. Like all best friends, JavaScript keeps its promises.
This may sound a little strange, but it's true. Most browsers currently support so-called Promise objects. A Promise is much like a function that represents a piece of code or a task that you want to execute at some point in the future.
This is what commitment looks like.
var myPromise = new Promise(function (resolve, reject) { // Task to carry out goes here. });
You can see here that when we create a Promise, we give it a parameter, which is a function that contains the code we want to execute at some point in the future. You may also notice the two parameters passed to the Promise in the function: resolve
and reject
. These are also functions, and are how we tell a Promise whether it's fulfilled. Here's how you use them:
var myPromise = new Promise(function (resolve, reject) { if (true) { resolve('Hello Tuts+ fans!'); } else { reject('Aww, didn\'t work.'); } });
This promise will obviously always be resolved, since the if
statement will always be true. This is just for learning purposes - we'll do something more practical later - but imagine replacing true
with a piece of code that you're not 100% sure is valid.
Now that we have created a Promise, how do we use it? Well, we need to tell it what the resolve
and reject
functions are. We do this by using Promise’s then
method.
myPromise.then(function (result) { // Resolve callback. console.log(result); }, function (result) { // Reject callback. console.error(result); });
Because our if statement always passes its true
check, the code above will always log "Hello Tuts fans!" to the console. It also executes immediately. This is because the code inside the Promise constructor is synchronous, meaning it does not wait for any operations to be performed. It has all the information it needs to proceed, and will do so as quickly as possible.
However, where Promise really shines is in asynchronous tasks, tasks where you don’t know when the Promise will actually be fulfilled. A real-world example of an asynchronous task is fetching a resource, such as a JSON file, via AJAX. We don't know how long it will take for the server to respond, or if it may even fail. Let's add some AJAX to our Promise code.
var myPromise = new Promise(function (resolve, reject) { // Standard AJAX request setup and load. var request = new XMLHttpRequest(); // Request a user's comment from our fake blog. request.open('GET', 'http://jsonplaceholder.typicode.com/posts/1'); // Set function to call when resource is loaded. request.onload = function () { if (request.status === 200) { resolve(request.response); } else { reject('Page loaded, but status not OK.'); } }; // Set function to call when loading fails. request.onerror = function () { reject('Aww, didn\'t work at all.'); } request.send(); });
The code here is just standard JavaScript for performing AJAX requests. We request a resource, in this case a JSON file at a specified URL, and wait for it to respond. We'll never know exactly when. We obviously don't want to stop executing the script to wait for it, so what do we do?
Fortunately, we have put this code into a Promise. By putting it here, we're basically saying, "Hey, a piece of code, I have to go now, but I'll call you later and tell you when to execute it. Promise you're going to do it and tell me you When will it be done?" The code will say: "Yes, of course. I promise."
The important thing to note in the above code is the call of the resolve
and reject
functions. Remember, these are how we tell our promises whether our code executed successfully. Otherwise, we'll never know.
Using the same code from the basic example, we can see how AJAX requests in Promise will now work.
// Tell our promise to execute its code // and tell us when it's done. myPromise.then(function (result) { // Prints received JSON to the console. console.log(result); }, function (result) { // Prints "Aww didn't work" or // "Page loaded, but status not OK." console.error(result); });
I know we can trust you, myPromise
.
Now, you might think that Promise is just a fancy callback function with better syntax. This is true to an extent, but to continue with our AJAX example, let's say you need to make a few more requests, each based on the results of the previous request. Or what if you need to process JSON first?
Doing this using callbacks will result in a lot of nesting of functions, each becoming increasingly difficult to track. Luckily, in the world of Promises, we can chain these functions together like this. Here's an example, once we receive the JSON of a user's comment on our fake blog, we need to make sure it's all lowercase before doing anything else with it.
myPromise .then(function (result) { // Once we receive JSON, // turn it into a JSON object and return. return JSON.parse(result); }) .then(function (parsedJSON) { // Once json has been parsed, // get the email address and make it lowercase. return parsedJSON.email.toLowerCase(); }) .then(function (emailAddress) { // Once text has been made lowercase, // print it to the console. console.log(emailAddress); }, function (err) { // Something in the above chain went wrong? // Print reject output. console.error(err); });
You can see here that although our initial call is asynchronous, it is also possible to chain synchronous calls. resolve
The code in the function will be called on each then
return. You will also notice that only one error function is specified here for the entire chain. By placing it at the end of the chain as the last then
in the reject
function, any Promise in the chain that calls reject
will call this function one.
现在我们对承诺更有信心了,让我们结合上面的承诺创建另一个承诺。我们将创建一个采用新的小写电子邮件地址的电子邮件地址,并(假装)向该地址发送电子邮件。这只是一个说明异步内容的示例 - 它可以是任何内容,例如联系服务器以查看电子邮件是否在白名单上或者用户是否已登录。我们需要将电子邮件地址提供给新的 Promise,但承诺不接受争论。解决这个问题的方法是将 Promise 包装在一个可以执行此操作的函数中,如下所示:
var sendEmail = function (emailAddress) { return new Promise(function (resolve, reject) { // Pretend to send an email // or do something else asynchronous setTimeout(function () { resolve('Email sent to ' + emailAddress); }, 3000); }); };
我们在此处使用 setTimeout
调用来简单地伪造一个需要几秒钟才能异步运行的任务。
那么我们如何使用新的承诺创建函数呢?好吧,由于在 then
中使用的每个 resolve
函数都应该返回一个函数,那么我们可以以与同步任务类似的方式使用它。
myPromise .then(function (result) { return JSON.parse(result); }) .then(function (parsedJSON) { return parsedJSON.email.toLowerCase(); }) .then(function (emailAddress) { return sendEmail(emailAddress) }) .then(function (result) { // Outputs "Email sent to stuart@fakemail.biz" console.log(result); }, function (err) { console.error(err); });
让我们回顾一下这个流程,总结一下发生了什么。我们最初的 Promise myPromise
请求一段 JSON。当收到该 JSON 时(我们不知道何时),我们将 JSON 转换为 JavaScript 对象并返回该值。
完成后,我们从 JSON 中取出电子邮件地址并将其变为小写。然后我们向该地址发送一封电子邮件,同样我们不知道它何时完成,但当它完成时,我们将向控制台输出一条成功消息。看不到沉重的嵌套。
我希望这是对 Promise 的有用介绍,并为您提供了在 JavaScript 项目中开始使用它们的充分理由。如果您想更详细地了解 Promise,请查看 Jake Archibald 关于这个主题的优秀 HTML5 Rocks 文章。
学习 JavaScript:完整指南
我们构建了一个完整的指南来帮助您学习 JavaScript,无论您是刚刚开始作为 Web 开发人员还是想探索更高级的主题。
The above is the detailed content of JavaScript: Keeping our word. For more information, please follow other related articles on the PHP Chinese website!