JavaScript Promises

转载自:http://wildermuth.com/2013/8/3/JavaScript_Promises

No I am not talking the promise that JavaScript will fix everything if you use it. I don't even believe that ;) I am talking about the concept of a promise object that several JavaScript libraries use (including AngularJSjQueryDojo and WinJS).

A promise is a pattern for handling asynchronous operations. The problem is that essentially when you start an asynchronous operation, you need to execute some code as the operation is completed. Asynchronous code is so common that most libraries have found a solution for passing in callbacks. But there is little commonality to how each libraries does this. Let's take jQuery as an example:

var $info = $("#info");

$.ajax({
    url:"/echo/json/",
    data: { json: JSON.stringify({"name": "someValue"}) },
    type:"POST",
    success: function(response)
    {
       $info.text(response.name);
    }
});

In this example you can see the jQuery uses the success property of the settings object to specify the callback. This isn't a promise but a way to pass in the callback functions. When the ajax call is complete, it calls the success function. Depending on the library that uses asynchronous operations, you might pass in a set of callbacks (e.g. for success or failure). There are a ton of ways to accomplish this.

The promise pattern sets out to simplify this process. The asynchronous operation simply returns an object called a promise. The promise allows you to call a method called then that let's you specify the function(s) to use as the callbacks. Let's see how to consume a promise using jQuery as an example:

var $info = $("#info");

$.ajax({
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.then(function (response) {
    $info.text(response.name);
});


What is interesting here, is that the object that ajax returns is the xhr object which implements the promise pattern so we can call then as seen here. The power of the call to then is that you can chain them by calling then for discrete operations and completing the operation with a call to done as shown here:

var $info = $("#info");

$.ajax({
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.then(function (response) {
    $info.text(response.name);
})
.then(function () {
    $info.append("...More");
})
.done(function () {
    $info.append("...finally!");
});

Because many libraries are starting to take on the promise pattern, handling asynchronous operations should be easier no matter what code you're writing (e.g. NodeJS, in-browser JS, etc.). But what does a promise look like from the other side?

One important key to the pattern is that the then function can accept two functions. The first is for the success callback; the second for the failure callback like so:

var $info = $("#info");

$.ajax({
    // Change URL to see error happen
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.then(function (response) {
    // success
    $info.text(response.name);
}, 
function () {
    // failure
    $info.text("bad things happen to good developers");
})
.always(function () {
    $info.append("...finally");
});

Notice that in jQuery we're using a call to always to specify that we want to be called whether the success or failure was called.

Let's see how using a promise looks. Here is an example from AngularJS:

var m = angular.module("myApp", []);

m.factory("dataService", function ($q) {
    function _callMe() {
        var d = $q.defer();

        setTimeout(function () {
            d.resolve();// 调用此方法说明是success,则在then中调用对应的success方法
            //defer.reject();//调用此方法说明是fail,则在then中调用对用的fail方法
        }, 100);

        return d.promise;// 返回Promise对象
    }

    return {
        callMe: _callMe
    };
});

function myCtrl($scope, dataService) {
    $scope.name = "None";
    $scope.isBusy = true;
    dataService.callMe()
      .then(function () {
        // Successful
        $scope.name = "success";
      }, 
      function () {
        // failure
        $scope.name = "failure";
      })
      .then(function () {
        // Like a Finally Clause
        $scope.isBusy = false;
      });
}

AngularJS uses an implementation (see the $q variable) that is started with a call to defer().  This returns an object that contains ways to mark a successful or failure condition as well as the promise itself. Notice that in the _callMe function the dvariable is created by calling $q.defer() then the d.promise is returned from the function so that the caller can call the promise methods (e.g. then). When the actual asynchronous operation is performed (in this case mocked up as asetTimeout call), we can use the resolve method on the defer'd object to tell the promise that we completed successfully (and therefore call the first function in the then method below). If we were to call reject, the second method (the failure call) would be called instead.

You can play with these examples in JSFiddle and see what you can make happen. Promises are a really simple and cool way to handle asynchronicity. What I really like about it is that it simplifies your code (so that you don't have the triangle of doom when you have to nest callback functions inside each other. This makes it easy.

个人小结:Promise 隐藏了异步调用,使用then方法使得程序看起来是顺序调用的


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值