【问题标题】:Make sure that the code is executed in the correct order JavaScript确保代码以正确的顺序执行 JavaScript
【发布时间】:2016-12-14 05:36:37
【问题描述】:

我有一个生成电子邮件的 javascript 函数。

如果电子邮件有附件,我会循环浏览这些附件,并且每次将一个附件上传到 Dropbox,而不是实际附加附件,而是在电子邮件正文中附加一个指向该文件的 Dropbox 链接。

(相关代码用反斜杠包裹)

self.email = function (action, contact) {
    var emailTo = contact.email();
    var attachment = "";
    var lineBreak = "%0D%0A";
    var signature = uvm.user().fullName() 
    var body;
    var dropboxLink = "";
    switch (action) {
        case "a":
            body = "aaaa";
            break;
        case "b": case "c":
            body "bbbccc";
            break;
        //////////The piece of code that I'm working on//////////
        default:
            $.each(self.checkedDocs(), function (key, doc) {
                self.service.getDropboxLink(doc, function (result) {
                    dropboxLink = result;
                    attachment += lineBreak + doc.documentDescription() + ": " + dropboxLink; 
                });
            });
        body = "Please click on the link(s) below to view your document(s): "
        //////////End//////////
         }
    attachment = attachment ? attachment + lineBreak + lineBreak : lineBreak;
    body += lineBreak + attachment + signature;
    window.location.href = "mailto:" + emailTo + "?subject=" + self.subject() + "&body=" + body;
}

这是getDropboxLink函数:

self.getDropboxLink = function (doc, callback) {
    $.ajax({
        url: "/API/dropbox/DropboxUpload",
        type: "POST",
        data: ko.toJSON(doc),
        contentType: "application/json",
        success: function (data) {
            callback(data);
        }
    });
}

此代码无法正常工作,如果案例为default 并且有电子邮件附件,则电子邮件是在我从 API 获取 Dropbox 链接之前生成的。

我可以将async=false 添加到 POST 请求中,这样可以解决问题,但不推荐使用 async=false

我认为我应该使用回调或承诺来执行此操作,但这很复杂,因为生成电子邮件的代码部分属于 switch 的所有 cases 并且对 API 的调用仅在default 部分。

如果actiondefault 我需要:

attachment = attachment ? attachment + lineBreak + lineBreak : lineBreak;
    body += lineBreak + attachment + signature;
    window.location.href = "mailto:" + emailTo + "?subject=" + self.subject() + "&body=" + body;

完成后发生:

$.each(self.checkedDocs(), function (key, doc) {
            self.service.getDropboxLink(doc, function (result) {
                dropboxLink = result;
                attachment += lineBreak + doc.documentDescription() + ": " + dropboxLink; 
            });
        });

如果操作是 abc 没关系。

我希望我很清楚。有什么建议吗?

非常感谢任何帮助。

【问题讨论】:

  • 异步的东西是虚拟的,一旦你的代码中有一个异步请求,整个调用链也必须是异步的。也就是说,你的功能应该像getDropBoxLinks().then(formatEmail).then(sendEmail)
  • 谢谢你,我很想用一个承诺来做,你能指导我多一点吗?

标签: javascript asynchronous callback promise


【解决方案1】:

您可以通过记录您仍需要获得多少异步回复的计数器来解决异步问题,并且只有当该数量达到零时,您才会继续生成输出。如果将输出生成代码放在(嵌套)函数中,则可以同步(对于非默认情况)和异步(对于默认情况,当计数器为零时)调用它:

self.email = function (action, contact) {
    var lineBreak = "%0D%0A";

    function openEmail(body, attachment) {
        attachment = attachment ? attachment + lineBreak + lineBreak : lineBreak;
        body += lineBreak + attachment + uvm.user().fullName();
        window.location.href = "mailto:" + contact.email() + "?subject=" + self.subject() + "&body=" + body;
    }

    switch (action) {
        case "a":
            openEmail("aaaa");
            break;
        case "b": case "c":
            openEmail("bbbccc");
            break;
        default:
            var attachment = "", 
                docs = self.checkedDocs(),
                count = docs.length;
            if (!count) { // treat the case where there are no attachments
                openEmail("No attachments");
                break;
            }
            $.each(docs, function (key, doc) {
                self.service.getDropboxLink(doc, function (dropboxLink) {
                    attachment += lineBreak + doc.documentDescription() + ": " + dropboxLink; 
                    if (--count == 0) { // last one:
                        openEmail("Please click on the link(s) below to view your document(s): ", attachment);
                    }
                });
            });
    }
}

承诺

您可以查看promises,它可以很好地处理异步任务。您将首先更改函数 getDropboxLink,使其返回 $.ajax() 调用的返回值,这是一个 jQuery 承诺。不再需要回调,也不再需要 success 处理程序。

然后在 email 函数中,您将对每个 promise 调用 then 方法以返回格式化的附件文本。 then 方法也返回一个promise,所有这些promise 都可以映射到一个数组中。使用$.when,您可以在所有这些承诺都已履行时收到信号。您在其回调中获得的参数将是您在 then 回调中返回的任何参数。

以下是进行这些调整的代码:

self.email = function (action, contact) {
    var lineBreak = "%0D%0A";

    function openEmail(body, attachment) {
        attachment = attachment ? attachment + lineBreak + lineBreak : lineBreak;
        body += lineBreak + attachment + uvm.user().fullName();
        window.location.href = "mailto:" + contact.email() + "?subject=" + self.subject() + "&body=" + body;
    }

    switch (action) {
        case "a":
            openEmail("aaaa");
            break;
        case "b": case "c":
            openEmail("bbbccc");
            break;
        default:
            var docs = self.checkedDocs();
            if (!docs.length) { // treat the case where there are no attachments
                openEmail("No attachments");
                break;
            }
            $.when.apply($, docs.map(function (doc) {
                return self.service.getDropboxLink(doc).then(function (dropboxLink) {
                    return lineBreak + doc.documentDescription() + ": " + dropboxLink;                 
                });
            })).done(function() {
                var attachment = [].join.call(arguments, '');
                openEmail("Please click on the link(s) below to view your document(s): ", attachment);
            });
    }
}

self.service.getDropboxLink = function (doc) {
    return $.ajax({
        url: "/API/dropbox/DropboxUpload",
        type: "POST",
        data: ko.toJSON(doc),
        contentType: "application/json"
    });
}

注意:您的代码同时引用了self.service.getDropboxLinkself.getDropboxLink(没有service)。请根据您的实际情况调整。

【讨论】:

  • 非常感谢,效果很好,我真的很想用一个承诺来做,但不知道该怎么做,所以我会等一下,也许我会得到另一个答案。非常感谢,这是一个很好、简单且有效的解决方案! :)
  • 添加承诺解决方案
  • 太棒了!!!太感谢了!!你真是个天才!!像魅力一样工作!只有一个问题——API 调用中的第二个url 参数是什么?搞错了?
  • 不客气 ;-)。啊,那个网址是我用来测试的网址。现已删除。
  • 我希望我能投票不止一次,这样一个清晰、解释清楚且很好的答案!谢谢!
【解决方案2】:

首先建议使用promise.all,但我会以旧方式解释。

window.location.href = xxx 会在你获得 dropbox 链接之前执行,所以首先你需要知道有多少异步调用,并且在每个 done 回调中,检查所有任务是否完成

var results = arr.map((x,index)=>{
  $.ajax(url,data,function(){
    results[index] = true
    if(results.every((x)=>x)){
      location.href=xxxx
    }
  })
  return false
})

【讨论】:

    猜你喜欢
    • 2016-08-06
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    • 2017-07-08
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多