如何将Asynchronous函数的结果作为deffered对象传递

时间:2017-11-12 18:47:13

标签: javascript arrays asynchronous

我正在试图使用Deffered对象,尤其是在必须对数组中的每个项目执行多个异步操作的情况下。在下面的代码中,我只希望能够在完成后访问异步数组的结果,在我的例子中,它是结果数组。

  • 解释下面的代码

    1. ListData 函数派生源数据,这是我打算操作的数组。
    2. getPictureComplete1 对上面数组中的每个项目执行异步操作( ListDataWithPicture
    3. 第2步的想法是在步骤1中为数组中的每个项目添加一个图像网址,然后将新数组用作第4步的输入
    4. 可以将图像打印到页面或对阵列执行其他操作

var mydeferred = $.Deferred();
var ListData = function (){    
    listName = 'TeamInfo';
       $.ajax({
             url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('"+listName+"')/items?$select=Name/Title,Name/Name,Name/Id,Name/EMail,Name/WorkPhone&$expand=Name/Id",
            type: "GET",
            headers: { "ACCEPT": "application/json;odata=verbose" },
            success: onQuerySucceded,
            error: onQueryFailed
        });
        return mydeferred.promise();
    }
var ListDataWithPicture = function(userId, callback) {
        // execute AJAX request
            $.ajax({
                url: _spPageContextInfo.siteAbsoluteUrl + "/_api/web/SiteUserInfoList/items?$filter=Id eq " + userId + "&$select=Picture",
                type: "GET",
                async: false,
                headers: { "ACCEPT": "application/json;odata=verbose" },
                success: function(data){
                    console.log("Starting async operation for " + userId);
                    var pictureLink = "";
                    var mydata = callback(data.d.results[0].Picture.Url);                    
                    return mydata
                },
            error: onQueryFailed
            });            
                   
    }
    
function onQuerySucceded (data){
    var PeopleCompleteList = [];
    for (i=0; i< data.d.results.length; i++) {
                    //check if the user exists if he does store the following properties name,title,workphone,email
                    if(data.d.results[i]['Name'] != null){
                        personName = data.d.results[i]['Name'].Name.split('|')[2];
                        userName = data.d.results[i]['Name']['Name'];
                        UserTitle = data.d.results[i]['Name']['Title'];
                        UserphoneNumber = data.d.results[i]['Name']['WorkPhone'];
                        UserEmail = data.d.results[i]['Name']['EMail'];
                        Id = data.d.results[i]['Name']['Id'];
                        PeopleCompleteList.push(PersonConstructor(personName, UserTitle, UserphoneNumber,UserEmail,Id));
                    } 
                }
    mydeferred.resolve(PeopleCompleteList);
}
 
function getPictureComplete1 (data){
            var def = new $.Deferred();
            var results = [];
            var expecting = data.length;
            data.forEach(function(entry, index) {
                //this is the asynchronous function
                ListDataWithPicture(entry.UserId, function(result) {
                    results[index] = {imageUrl: result, UserId: entry.UserId, name: entry.name, Title: entry.Title, phoneNumber: entry.phoneNumber, Email: entry.Email};
                    //console.log(result);
                    if (--expecting === 0) {
                    // Done!
                    console.log("Results:", results); //this works succeffully from here 
                    def.resolve();
                    return results
                    //mydeferred.resolve(results);
                }
                });

            });
            return mydeferred.promise(); 
}


$(function () {
       ListData().then(function(data){
           //how can i access the results array in this function after it has completed??          
           var value = getPictureComplete1 (data);
           //the line below results undefined,which i understand because the getPictureComplete1 function may not have completed at the time
           console.log(value);
    });

1 个答案:

答案 0 :(得分:0)

因为这是一次异步操作,所以您唯一有权访问ajaxLineData调用的结果数组属于您onQuerySucceded函数的范围内分配到success配置中的ajax属性。在收到成功的响应后,您将在此处定义的函数被触发。

在建立延期承诺时,您需要定义哪些数据可以解析承诺。无论您传入resolve方法的是什么,都可以作为承诺链中后续块中的参数。

我没有在您的示例中看到onQuerySucceded,但它看起来像这样:

var ListData = function (){
   var mydeferred = $.Deferred();
   listName = 'TeamInfo';
   $.ajax({
         url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('"+listName+"')/items?$select=Name/Title,Name/Name,Name/Id,Name/EMail,Name/WorkPhone&$expand=Name/Id",
        type: "GET",
        headers: { "ACCEPT": "application/json;odata=verbose" },
        success: function onQuerySuccess(data) {
           mydeferred.resolve(data);
        },
        error: onQueryFailed
    });
    return mydeferred.promise();
}

现在,在成功通话后,承诺将解决数据。所以,这样的事情是可能的:

ListData()
   .then(function (data) {
      // do something with the data
   })

同样,您需要定义延期承诺的拒绝案例。例如,也许ajax调用不成功。为此,您需要在reject对象上使用deferred方法。

例如:

var ListData = function (){    
   var mydeferred = $.Deferred();
   listName = 'TeamInfo';
   $.ajax({
         url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('"+listName+"')/items?$select=Name/Title,Name/Name,Name/Id,Name/EMail,Name/WorkPhone&$expand=Name/Id",
        type: "GET",
        headers: { "ACCEPT": "application/json;odata=verbose" },
        success: function onQuerySuccess(data) {
           mydeferred.resolve(data);
        },
        error: function onQueryFailed(error) {
           mydeferred.reject(error);
        }
    });
    return mydeferred.promise();
}

这与解决方法类似,但会解析为任何后续catchfail块。所以,这样的事情会起作用

LineData()
    .then(function (data) {
        // it was successful, do something with the data
    })
    .catch(function (error) {
        // There was an error. The then block was not called.
        // Do something with the error.
    })

更简单地说,您可以直接将mydeferred.resolvemydeferred.reject设置为这些属性。像这样:

var ListData = function (){    
   var mydeferred = $.Deferred();
   listName = 'TeamInfo';
   $.ajax({
      url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('"+listName+"')/items?$select=Name/Title,Name/Name,Name/Id,Name/EMail,Name/WorkPhone&$expand=Name/Id",
      type: "GET",
      headers: { "ACCEPT": "application/json;odata=verbose" },
      success: mydeferred.resolve,
      error: mydeferred.reject
   });
   return mydeferred.promise();
}

您需要对ListDataWithPicture函数执行类似操作,以便它还返回包含所需数据的承诺:

var ListDataWithPicture = function(userId, callback) {
    var deferred = $.Deferred();
    $.ajax({
        url: _spPageContextInfo.siteAbsoluteUrl + "/_api/web/SiteUserInfoList/items?$filter=Id eq " + userId + "&$select=Picture",
        type: "GET",
        async: false,
        headers: { "ACCEPT": "application/json;odata=verbose" },
        success: function(data){
            deferred.resolve(data.d.results[0].Picture.Url)
        },
        error: deferred.reject
    });            
    return deferred.promise();
}

这允许你做这样的事情:

LineData()
    .then(function (data) {
        // performing on just the first result:
        return ListDataWithPicture(data[0]);
    })
    .then(function (url) {
        // do something with the result
    })
    .catch(function (error) {
        // do something with the error
    });

因为你想对数组中的每个项执行异步操作,所以我建议使用Promise.all来执行和解析一组promise。

LineData()
    .then(function (data) {
        // create a map of promises
        var promises = data.map(function (item) {
            return ListDataWithPicture(item);
        });
        return Promise.all(promises);
    })
    .then(function (urls) {
        // urls will be an array of urls resolved from calling 
        // ListDataWithPicture on each item in the array resolved
        // from above
    })
    .catch(function (error) {
        // do something with the error
    });

以下是一些了解更多资源的好资源: