This is a series of articles that you can keep up to date with by subscribing to the JavaScript Asynchronous Programming Guide on May Jun.

Promises are one of the most important concepts in modern JavaScript, and you might wonder why Deferred? What is this? In case you haven’t heard of Deferred promises, PromiseA+ is the evolutionary form of Deferred promises.

Learn about promises

In this section, you can follow me to find out what the Deferred is. I think it will be helpful for you to learn Promise in the future, and you will have more understanding of its history and more profound memory. React, Vue, Jquery, React, Vue, Vue, React, Vue, Vue, Vue, Vue, React, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue

Promise has existed in many forms in many languages. The word was first used by C++ engineers in the Xanadu project and later in E, which inspired Python to implement it as a Deffered object in the Twisted framework.

Promise jumped on the JavaScript bandwagon in 2007, when Twisted’s Dojo framework added an object called Dojo.Deferred. At the time, the relatively mature Dojo rivaled the fledgling Jquery in popularity, and while the Deferred pattern first appeared in Dojo code, it is widely known to come from Jquery version 1.5, This is also a major turning point in Jquery, with the introduction of a new feature called Deferred, which completely changes how Ajax is used in Jquery and almost rewrites the Ajax part of Jquery.

In 2009 Kris Zyp, aware of the influence of Dojo.Deferred, abstracted the pattern as A draft proposal, published in the CommonJS specification, and later abstracted the Promise/A specification, the same year node.js made its debut.

Early iterations of Node.js used promises in non-blocking apis. However, in February 2010, Early Node.js author Ryan Dahl decided to switch to the now-familiar callback(Err, result) because promises were a higher-level construct of “user area,” So early on you’ll see a lot of apis in Node.js as callback(Err, result), and still do. By the way, Ryan Dahl left the Node.js community in 2012, Node.js has been managed by the Node.js Foundation since 2021, and many changes have been made to Node.js, including file manipulation and Promise apis, Stream now supports asynchronous iteration, You don’t need to nest your program with callback.

Ryan Dahl’s decision at the time set the stage for promising implementations that competed with Node.js, such as Q.js, which was A fairly simple implementation based on the Promise/A specification for A while. Futures is a broader toolkit containing many of the process control features provided in libraries such as Async.js.

In the previous section, we talked about how in the early days, we used Callback to make network requests to the server, and then used the registered Callback function to get the returned data. We also mentioned that the Callback function based on Callback was very easy to create nested Callback functions and difficult to handle errors. Now let’s take a look at how the earlier Jquery solution of Deferred works and how it relates to the Promise we’ll explain later.

Deferred objects in Ajax

Jquery 1.5 Jquery 1.5

// Returns an XHR object
$.ajax({
  url: "http://openapi.xxxxxx.com/api".success: function(){
    console.log("success!");
  },
  error:function(){
    console.log("failed!"); }});Copy the code

Jquery 1.5 ajax

// Returns the Deferred object
$.ajax("http://openapi.xxxxxx.com/api")
	.done(function(){ console.log("success1!"); })
	.fail(function(){ console.log("failed1!"); })
	.done(function(){ console.log("success2!"); })
	.fail(function(){ console.log("failed2!"); })
Copy the code

Writing in chained style greatly improves the reading experience, and does solve the callback hell problem compared to callback nesting, where done() was the previous success() method and fail() was the previous error() method.

Those of you who know Promise can see that doesn’t it feel a little bit like that? Let’s modify the.then() method:

$.ajax("http://openapi.xxxxxx.com/api")
	.then(function(){ console.log("success1!"); }, function(){ console.log("failed1!"); })
	.then(function(){ console.log("success2!"); }, function(){ console.log("failed2!"); })
Copy the code

Is it more like Promise?

Encapsulate a Deferred object of its own

The execution of the Deferred object divides the states into three: unfinished, completed, and failed. Calling DTD.resolve () changes the execution state to completed, invoking the callback specified by the done() method. Executing DTD.reject () changes the execution state to failed, calling the callback function specified by the fail() method.

const wait = () = > {
  const dtd = $.Deferred();
  const tasks = () = > {
    console.log('do something... ')
  	dtd.resolve(); // The execution status of the Deferred call is completed
    Dtd.reject () can also be called if there is an error;
  }
  
  setTimeout(tasks,5000);
  return dtd;
}
Copy the code

Wait now returns a Deferred object, which can be chained. Here we use DTD.then (), which already covers both the done() and fail() methods.

const d = wait()
  d.then(() = > {
  	console.log('success1');
	}, err= > {
		console.error('failed1')
	})
	.then(() = > {
  	console.log('success2');
	}, err= > {
		console.error('failed2')})Copy the code

After about 5 seconds of running the program, our results look like this:

do something...
success1
success2
Copy the code

Now there’s another problem. I can add a line d.resolve() at the end of the code; This changes the results of the program because we change the execution state externally.

constd = wait() d.then(...) ;// As above, this is omitted
d.resolve();

// Run the result
success1
success2
do something...
Copy the code

To avoid this, jQuery 1.5 provides the deferred.promise() method, which returns a deferred promise on a deferred object, using only methods that are independent of the execution state. For example, dtD.then () or dtd.done(), dtD.fail () methods. The methods dtd.resolve() and DTD.reject () related to execution state are masked.

const wait = () = >{...return dtd.promise();
}
Copy the code

conclusion

Deferred objects have dtd.resolve(), dtd.reject(), active firing functions related to execution state, and dtD.then () or DTD.done (), dtD.fail (), passive listening functions, all in one place. It is easy to appear externally tampered with as shown in the example above. The solution is to return a DTD.Promise () object that listens passively but does not actively modify the execution state.

As you’ll see in this article, this is very similar to the Promise/A+ specification we use today, which is A prehistory of the Promise/A+ specification.

Rerefence

  • Medium.com/pragmatic-p…
  • www.ruanyifeng.com/blog/2011/0…

The JavaScript Asynchronous Programming Guide – You didn’t know the Promise was Deferred. You can subscribe to the JavaScript Asynchronous Programming Guide via may Jun for the latest information. If you have any questions or better suggestions, you can also add my wechat codingMay for discussion.