Using promise to solve the simple learning _javascript skills of multilayer asynchronous invocation

Source: Internet
Author: User
Tags call back documentation readfile

Objective

The first contact with promise this thing, is the 2012 Microsoft released WINDOWS8 operating system after the death of the curious mentality of HTML5 write Metro applications. At that time with the HTML5 provided by the WINJS library inside the asynchronous interface are all promise form, which was just graduated a little javascript basis for me is simply a heavenly book. What I was thinking was that Microsoft was in a hole in the brain.

The result did not expect, to 2015 years, promise incredibly write into ES6 standard inside. And a survey shows that JS programmers use this thing is very high.

Ironically, as early as in 2012 in the Metro application development interface in the extensive use of promise Microsoft, its own browser ie until the end of the 2015 is not support promise, it seems that Microsoft is not without this technology, but really to ie give up treatment ...

Now looking back, then see promise most headaches, is the beginner looks strange, but also the most widely praised by JS programmers features: Then function call chain.

The then function call chain, in essence, is the sequential invocation of multiple asynchronous processes, this article starts from this point, to study and study the characteristics of promise.

Promise Solve the problem

Consider the following scenario, function delay 2 seconds after printing a row of log, and then 3 seconds to print a row of log, and then delay 4 seconds to print a row of logs, which in other programming languages is very simple things, but to the JS inside is more laborious, the code will be written about the following:

var myfunc = function () {  
  settimeout (function () {
    console.log ("Log1");
    settimeout (function () {
      console.log ("log2");
      settimeout (function () {
        console.log ("Log3");
      }, 4000);},
    3000)
;}

A typical pyramid structure is formed here because of nested multiple callback structures. If the business logic is more complex, it will become a fearsome callback to hell.

If consciousness is better, and you know how to extract a simple function, then the code is almost like this:

var func1 = function () {
  settimeout (FUNC2, Watts);

var func2 = function () {
  console.log ("Log1");
  SetTimeout (FUNC3, 3000);
};

var func3 = function () {
  console.log ("log2");
  settimeout (FUNC4, 4000);
};

var func4 = function () {
  console.log ("Log3");

It looks a little bit better, but it always feels a little weird ... Well, in fact, my JS level is limited, I can't say why this is not good to write. If you know why it's not so good to write promise, please tell me.

Now let's get to the promise of this thing.

Description of the Promise

Here, allow me to quote MDN's description of promise:

The Promise object is used for deferred (deferred) and asynchronous (asynchronous) computations. A Promise object represents an action that has not yet been completed but is expected to be completed in the future.

The Promise object is a proxy that returns a value that is not necessarily known when the Promise object is created. It allows you to specify the processing method for the success or failure of an asynchronous operation. This allows the asynchronous method to return a value like a synchronous method: The asynchronous method returns a Promise object that contains the original return value instead of the original return value.

The Promise object has several states:

pending: Initial state, not fulfilled or rejected.
fulfilled: A successful operation.
rejected: failed operation.

The Promise object of the pending state can be converted either to a fulfilled state with a success value or to a rejected state with a failure message. When the state transitions, the Promise.then-bound method (the function handle) is invoked. (When binding methods, if the Promise object is already in the fulfilled or rejected state, then the corresponding method will be called immediately, so there is no competition condition between the completion of the asynchronous operation and its binding method.) )

More descriptions and examples of promise can refer to MDN promise entries or MSDN promise entries.

Try to use promise to solve our problems

Based on the above understanding of promise, we know that it can be used to solve the problem that the multi-layer callback nesting code is too stupid to maintain. The two links given above for the syntax and parameters of promise have been made clear, not repeated here, directly on the code.

Let's try a simpler scenario where we only perform a delay and a callback:

New Promise (function (res, REJ) {
  console.log (Date.now () + "Start settimeout");
  SetTimeout (res, Watts);
}). Then (function () {
  console.log (Date.now () + "Timeout call back");

It looks like the examples in MSDN are no different, and the results are as follows:

$ node Promistest.js
1450194136374 start settimeout
1450194138391 timeout Call back

So if we're going to do another delay, then I can write this:

New Promise (function (res, REJ) {
  console.log (Date.now () + "start settimeout 1");
  SetTimeout (res, Watts);
}). Then (function () {
  console.log (Date.now () + "Timeout 1 call back");
  New Promise (function (res, REJ) {
    console.log (Date.now () + "Start settimeout 2");
    settimeout (res, 3000);
  }). Then (function () {
    console.log (Date.now () + "Timeout 2 call back");
  })
;

Also seems to work correctly:

$ node Promistest.js
1450194338710 start settimeout 1
1450194340720 timeout 1 call back
1450194340720 start s Ettimeout 2
1450194343722 Timeout 2 call back

But the code looks silly and silly, and vaguely in the pyramid again. This is contrary to the purpose of introducing promise.

So what's the problem? What about the right posture?

The answer is hidden in the return value of the then function and the onfulfilled (or oncompleted) callback function of the then function.

The first thing to be clear is that the then function returns a new promise variable, and you can call the then function of the new promise variable again, like this:

New Promise (...). Then (...)
  . Then (...). Then (...). Then (...) ...

What kind of promies the then function returns depends on the return value of the onfulfilled callback.

In fact, onfulfilled can return either a normal variable or another promise variable.

If onfulfilled returns a normal value, the then function returns a default promise variable. The then function that executes this promise causes promise to be satisfied immediately, executing the onfulfilled function, and the onfulfilled's entry, which is the return value of the previous onfulfilled.

And if onfulfilled returns a promise variable, that promise variable will be the return value of the then function.

For this set of settings for the return value of the then function and the onfulfilled function, there is no explicit positive description of the documentation on MDN and MSDN, as ES6 official documentation ECMAScript 2015 (6th Edition, ECMA-262) ... My level is limited really can't understand, if which expert can explain clearly in the official document face two return value description, please certain message advice!!!

So the above for my free play, language organization is a bit awkward, on the code to see everyone understand.

The first is to return the normal variable:

New Promise (function (res, REJ) {
  console.log (Date.now () + "start settimeout 1");
  SetTimeout (res, Watts);
}). Then (function () {
  console.log (Date.now () + "Timeout 1 call back");
  return 1024;
}). Then (function (ARG) {
  console.log (Date.now () + "Last onfulfilled return" + arg);  
});

The above code execution results are:

$ node Promistest.js
1450277122125 start settimeout 1
1450277124129 timeout 1 call back
1450277124129 Last onfulfilled return 1024

That's not the point, right? The key is that the onfulfilled function returns a promise variable that makes it convenient for us to invoke multiple asynchronous processes in succession. For example, we can try to do two consecutive delay operations:

New Promise (function (res, REJ) {
  console.log (Date.now () + "start settimeout 1");
  SetTimeout (res, Watts);
}). Then (function () {
  console.log (Date.now () + "Timeout 1 call back");
  return new Promise (function (res, REJ) {
    console.log (Date.now () + "Start settimeout 2");
    settimeout (res, 3000);
  });
Then (function () {
  console.log (Date.now () + "Timeout 2 call back");

The results of the implementation are as follows:

$ node Promistest.js
1450277510275 start settimeout 1
1450277512276 timeout 1 call back
1450277512276 Start settimeout 2
1450277515327 Timeout 2 call back

If you don't think it's a big deal, it's just a few more times:

New Promise (function (res, REJ) {
  console.log (Date.now () + "start settimeout 1");
  SetTimeout (res, Watts);
}). Then (function () {
  console.log (Date.now () + "Timeout 1 call back");
  return new Promise (function (res, REJ) {
    console.log (Date.now () + "Start settimeout 2");
    settimeout (res, 3000);
  });
Then (function () {
  console.log (Date.now () + "Timeout 2 call back");
  return new Promise (function (res, REJ) {
    console.log (Date.now () + "start settimeout 3");
    settimeout (res, 4000);
  });
Then (function () {
  console.log (Date.now () + "Timeout 3 call back");
  return new Promise (function (res, REJ) {
    console.log (Date.now () + "start settimeout 4");
    settimeout (res, 5000);
  });
Then (function () {
  console.log (Date.now () + "Timeout 4 call back");

$ node Promistest.js
1450277902714 start settimeout 1
1450277904722 timeout 1 call back
1450277904724 start s Ettimeout 2
1450277907725 timeout 2 call back
1450277907725 start settimeout 3
1450277911730 Timeout 3 call BA CK
1450277911730 start settimeout 4
1450277916744 Timeout 4 call back

As you can see, multiple deferred callback functions are arranged in an orderly fashion, and there is no pyramid-like structure. Although the code calls an asynchronous procedure, it looks like it's all made up of the synchronization process. This is the benefit that promise brings to us.

If you have a good habit of refining verbose code into a separate function, it's more beautiful than it looks:

 function timeout1 () {return new Promise (function (res, REJ) {Console.log (Date.now ()
    + "Start timeout1");
  SetTimeout (Res, 2000);
});
    function Timeout2 () {return new Promise (function (res, REJ) {Console.log (Date.now () + "Start Timeout2");
  settimeout (res, 3000);
});
    function Timeout3 () {return new Promise (function (res, REJ) {Console.log (Date.now () + "Start Timeout3");
  settimeout (res, 4000);
});
    function Timeout4 () {return new Promise (function (res, REJ) {Console.log (Date.now () + "Start Timeout4");
  settimeout (res, 5000);
}); } timeout1 (). Then (TIMEOUT2). Then (TIMEOUT3). Then (TIMEOUT4). Then (function () {Console.log (Date.now () + "Ti
  MOUT4 callback "); 
});
$ node Promistest.js
1450278983342 start timeout1
1450278985343 start timeout2
1450278988351 start TIMEOUT3
1450278992356 start timeout4
1450278997370 Timout4 Callback

We can then go on to examine the problem of onfulfilled function incoming parameters.

As we already know, if the last onfulfilled function returns a normal value, then the value is taken as an argument to the onfulfilled function; If the previous onfulfilled returns a Promise variable, Where does this onfulfilled come from?

The answer is that the onfulfilled of this function is the value that was passed in when the resolve function was called in the previous promise.

Jumping a little big time can not accept the right, let us have a good wisp of Ray.

First, promise.resolve What this function is, using the MDN above Wen

Resolves a promise object with a value of success. If the value is a sustainable (thenable, with then method), the returned Promise object "follows" this value

In short, this is the callback in case of a successful asynchronous invocation.

Let's take a look at the normal asynchronous interface, the success of the callback is what kind of, taking Nodejs's Fs.readfile (file[, Options), callback), its typical invocation examples are as follows

Fs.readfile ('/etc/passwd ', function (err, data) {
 if (err) throw err;
 Console.log (data);

Because for fs.readfile this function, regardless of success or failure, it will call callback this callback function, so this callback accepts two parameters, that is, the failure of the exception description err and success of the return result data.

So what should we do if we use promise to refactor this example of reading a file?

The first is to encapsulate the Fs.readfile function:

function readFile (filename) {return
  new Promise (function (resolve, reject) {
    fs.readfile (filename, function ( Err, data) {
      if (err) {
        reject (err);
      } else {
        resolve (data);
      }
    }
);}

Next is the call:

ReadFile (' TheFile.txt '). Then (
  function (data) {
    console.log (data);
  }, 
  function (err) {
    throw err;
  }  
);

Imagine where the contents of a file are usually placed in the synchronous calling interface of a read file in another language. function return value Right! The answer comes out, what is this resolve's entry? is the return value in the case of a successful asynchronous call.

With this concept, it's not hard to understand that "the onfulfilled function is the value passed in when the resolve function was called in the previous promise." Because Onfulfilled's task is to deal with the result of the last asynchronous call succeeding.

Hey finally straighten out ...

Summarize

Let me summarize the main points in this article with a piece of code:

 function Callp1 () {Console.log (Date.now () + "Start Callp1");
  return new Promise (function (res, REJ) {settimeout (res, 2000);
});
  function Callp2 () {Console.log (Date.now () + "Start Callp2");
    return new Promise (function (res, REJ) {settimeout (function () {res ({arg1:4, arg2: "Arg2 Value"});
  }, 3000);
});
  function Callp3 (ARG) {Console.log (Date.now () + "start callp3 with arg =" + arg);
    return new Promise (function (res, REJ) {settimeout (function () {res ("callp3");
  }, ARG * 1000);
});
  CALLP1 (). Then (function () {Console.log (Date.now () + "CALLP1 return");
return CALLP2 ();
  }). Then (function (ret) {Console.log (Date.now () + CALLP2 return with ret value = "+ json.stringify (ret));
Return Callp3 (RET.ARG1); }). Then (function (ret) {Console.log (Date.now () + CALLP3 return with ret value = "+ ret);}" 
$ node Promistest.js
1450191479575 start callp1
1450191481597 callp1 return
1450191481599 start CALLP2
1450191484605 CALLP2 return with ret value = {"Arg1": 4, "arg2": "Arg2 Value"}
1450191484605 start callp3 with arg = 4
1450191488610 callp3 return with ret value = CALLP3

The above article uses promise to solve multi-layer asynchronous call simple learning experience is small series share to everyone's content, hope to give you a reference, also hope that we support cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.