Magren

Magren

Idealist & Garbage maker 🛸
twitter
jike

Promise in es6

Promise, in simple terms, is a container that holds the result of an event (usually an asynchronous operation) that will only end in the future. Syntax-wise, a Promise is an object that can retrieve messages from an asynchronous operation.

With Promise objects, asynchronous operations can be expressed in a synchronous flow, avoiding the need for nested callback functions. Additionally, Promise objects provide a unified interface that makes controlling asynchronous operations easier.

However, Promises also have some drawbacks:

  1. Firstly, Promises cannot be cancelled. Once created, they will immediately execute and cannot be cancelled midway.
  2. If no callback function is set, errors thrown internally by the Promise will not be reflected externally.
  3. When in the pending state, it is not possible to know which stage the operation is currently at (just started or about to complete).

Characteristics of Promises#

  1. The state of the object is not affected by external factors. A Promise object represents an asynchronous operation and has three states: pending (in progress), fulfilled (successfully completed), and rejected (failed).
  2. Once the state changes, it will not change again, and the result can be obtained at any time. When the state of a Promise object changes, it either succeeds or fails. Once one of these two conditions occurs, the state solidifies and becomes resolved. After the change occurs, even if a callback function is added, the result will still be obtained.

Usage#

Creating a Promise instance#

A Promise object is a constructor used to generate Promise instances.

const promise = new Promise(function(resolve, reject) {
  if (/* asynchronous operation successful */){
    resolve(value);
  } else {
    reject(error);
  }
});

The resolve function is used to change the state of the Promise object from "pending" to "resolved" (from pending to resolved) and is called when the asynchronous operation is successful. It passes the result of the asynchronous operation as a parameter.

The reject function is used to change the state of the Promise object from "pending" to "rejected" (from pending to rejected) and is called when the asynchronous operation fails. It passes the error thrown by the asynchronous operation as a parameter.

then method#

Next, use the then method to specify the callback functions for the resolved and rejected states:

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

The first function is called when the state object changes to rejected, the second function is called when it changes to resolved, and the second function is optional.

The then method returns a new Promise instance (note that it is not the original Promise instance). Therefore, it can be used in a chain, where another then method is called after the first one.

promise.then(function(value) {
  
}.then(function (comments) {
  console.log("resolved: ", comments);
}, function (err){
  console.log("rejected: ", err);
});

catch method#

Used to specify the callback function when an error occurs.

promise.then(function(value) {
  // success
}, function(error) {
  // failure
}).catch(function(error) {
  // handle the error that occurred
  console.log('An error occurred!', error);
});

If the asynchronous operation throws an error, the state will change to rejected and the callback function specified in catch() will be called to handle the error. Additionally, if the callback function specified in then() throws an error during execution, it will also be caught by catch().

Unlike traditional try/catch blocks, if no callback function is specified to handle errors using catch(), the errors thrown by the Promise object will not be passed to the outer code and will not trigger any response.

finally method#

Used to specify operations that will be executed regardless of the final state of the Promise object.

promise.then(function(value) {
  // success
}, function(error) {
  // failure
}).catch(function(error) {
  // handle the error that occurred
  console.log('An error occurred!', error);
}).finally(function(){
    alert("finish");
});

The callback function of the finally method does not accept any parameters, meaning that the final state cannot be determined.

Example with jQuery, Ajax, and Promises#

I previously learned about jQuery and Ajax, so I decided to test an API I found online:

const apiUrl = "https://suggest.taobao.com/sug?code=utf-8&q=电脑&callback=cb";
$("##bt").click(apiUrl,function(event){
     const promise = new Promise(function(resolve,reject){
       $.ajax({
           url: event.data,
           type:"get",
           dataType:"jsonp",
           headers: {      
                       Accept: "application/json; charset=utf-8",
                   },
           success: function(data) {
            resolve(data);   
           },
           error: function(XMLHttpRequest, textStatus, errorThrown) {
               reject(XMLHttpRequest,textStatus,errorThrown)
           },
       })
   })

   promise.then(function(data){
       console.log(data);
       let x = data.result;
       for(let i = 0 ; i<data.result.length;i++){
           console.log(x[i][0]);
       }
   },function(XMLHttpRequest, textStatus, errorThrown){
       alert(XMLHttpRequest);
       alert(textStatus);
       alert(errorThrown);
   }).catch(function(error){
       console.log(error);
   }).finally(function(){
       alert("finish");
   });
});

Result:

Issues Encountered#

I didn't have any major issues with learning the basics of Promises, but I did encounter a cross-origin issue when making the Ajax request. The error message was:

Access to XMLHttpRequest at 'API URL' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

What is this...?

After some research, I learned about the concept of cross-origin requests:

Each website can only read data from the same origin, where the same origin refers to the combination of hostname (domain), protocol (http/https), and port number. Without explicit authorization, it is not possible to read or write resources from another origin. This is the core and fundamental security feature of browsers. Each website can only read data from the same origin, where the same origin refers to the combination of hostname (domain), protocol (http/https), and port number. Without explicit authorization, it is not possible to read or write resources from another origin. This is the core and fundamental security feature of browsers. Asynchronous XMLHttpRequest is subject to the same-origin policy, meaning it can only access data from the same origin. Therefore, the error was thrown.

So how do we solve this?

Most of the articles I found suggested setting up request permissions with the backend, but in my case, I was using a public API... How could I ask someone to do this and that for me?

I finally found a solution: jsonp.

JSONP:

  • Loads data by including a script tag, which is synchronous. When using a script tag for cross-origin requests, it is not recommended to preload the data. It should be loaded on-demand.
  • When data is needed, create a script tag and put the required data in the src attribute. Use the onload event to listen for the data to be requested, and once it is loaded, call the callback function to pass the data back (asynchronous loading).
  • JSONP can only be used for GET requests, not POST requests.

So why does this type of request work for cross-origin?

Tags with src attributes, such as script, img, iframe, and link, are not subject to the same-origin policy. However, the browser restricts the permissions of JavaScript loaded through src, allowing it to read but not write.

In summary, changing the dataType from json to jsonp solved the cross-origin issue.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.