WinJS,从函数中返回一个可能是也可能不是异步的函数

时间:2013-12-18 16:21:30

标签: javascript asynchronous winjs promise

我的情况是我的WinJS应用程序要调用一个可能是也可能不是异步的函数(例如,在一种情况下我需要从文件中加载一些数据(异步)但在其他时候我可以从缓存加载syncronously)。

浏览文档我虽然可以将条件逻辑包装在一个承诺中:

A)
return new WinJS.Promise(function() {  // mystuff });

或可能使用'作为'像这样:

B)
return WinJS.Promise.as(function() { // mystuff });

问题在于,当我调用此函数时,我正在执行第一页的ready()函数,如下所示:

WinJS.UI.Pages.define("/pages/home/home.html", {

    ready: function () {

         Data.Survey.init().done(function (result) {

            // do some stuff with 'result'

        });
    }
 });

当它被写成' A'它永远不会打到我的done()调用。

或者如果我把它称为' B'它会立即执行我的done()中的代码,然后才能解决诺言。它还从结果的值看,它刚刚被设置为我的init()函数的内容,而不是被包含在一个promise中。

感觉我在这里做了一些完全错误的事情,但我不确定从哪里开始寻找。

如果有任何帮助,这是我的init()函数的精简版本:

    function init() {

    return new WinJS.Promise(function() {

        if (app.context.isFirstRun) {

            app.surveyController.initialiseSurveysAsync().then(function (result) {
                return new WinJS.Binding.List(result.surveys);
            });
        } else {

            var data = app.surveyController.getSurveys();
            return new WinJS.Binding.List(data);
        }
    });
}  

有没有人对此有任何想法?我不相信这可能是也可能不是异步'这是问题,我相信承诺设置并不是我所期望的。谁能在这里看到任何明显错误的东西任何反馈都非常感谢。

1 个答案:

答案 0 :(得分:7)

一般来说,如果您在完整的初始化例程中执行文件I / O,那些API本身会返回promise,在这种情况下,您希望从其中一个.then方法返回其中一个promise或promise。

另一方面,WinJS.Promise.as旨在将一个值包装在一个promise中。但让我更充分地解释一下。

首先,仔细阅读WinJS.Promise构造函数的文档。像许多其他人一样,你错误地认为你只是在承诺中包含一段代码而瞧!它是异步的。不是这种情况。传递给构造函数的函数是一个初始化程序,它接收三个参数:一个completeDispatcher函数,一个errorDispatcher函数和一个progressDispatcher函数,我喜欢称之为。

对于成功完成的承诺,完成错误或报告进度,初始化程序中的其余代码最终必须调用其中一个调度程序。这些调度程序在promise中,然后遍历并调用任何完成/错误/进度方法,这些方法已经被赋予了该promise或者已经完成的方法。因此,如果您根本不打电话给调度员,则无法完成,这正是您所看到的行为。

使用WinJS.Promise.as类似,它将包装在promise中。在您的情况下,如果您将一个函数传递给WinJS.promise.as,那么您将获得的是一个承诺,即该函数值的结果。你得到函数的异步执行。

要实现异步行为,您必须使用setTimeout / setInterval(或Windows 8.1中的WinJS调度程序)在UI线程上执行异步工作,或者使用Web worker作为后台线程并将其完成(通过postMessage)成为一个承诺。

以下是使用构造函数创建承诺,处理完整,错误和进度案例(以及取消)的完整示例:

    function calculateIntegerSum(max, step) {
    if (max < 1 || step < 1) {
        var err = new WinJS.ErrorFromName("calculateIntegerSum", "max and step must be 1 or greater");
        return WinJS.Promise.wrapError(err);
    }

    var _cancel = false;

    //The WinJS.Promise constructor's argument is a function that receives 
    //dispatchers for completed, error, and progress cases.
    return new WinJS.Promise(function (completeDispatch, errorDispatch, progressDispatch) {
        var sum = 0;

        function iterate(args) {
            for (var i = args.start; i < args.end; i++) {
                sum += i;
            };

            //If for some reason there was an error, create the error with WinJS.ErrorFromName
            //and pass to errorDispatch
            if (false /* replace with any necessary error check -- we don’t have any here */) {
                errorDispatch(new WinJS.ErrorFromName("calculateIntegerSum", "error occurred"));
            }

            if (i >= max) {
                //Complete--dispatch results to completed handlers
                completeDispatch(sum);
            } else {
                //Dispatch intermediate results to progress handlers
                progressDispatch(sum);

                //Interrupt the operation if canceled
                if (!_cancel) {
                    setImmediate(iterate, { start: args.end, end: Math.min(args.end + step, max) });
                }
            }
        }

        setImmediate(iterate, { start: 0, end: Math.min(step, max) });
    },
    //Cancellation function 
    function () {
        _cancel = true;
    });
}

这来自我的免费电子书附录A(&#34; Demystifying Promises&#34;),用HTML,CSS和JavaScript编写Windows应用商店应用程序,第二版(预览版),见http://aka.ms/BrockschmidtBook2

在您的情况下,您可以将数据初始化代码放在iterate函数的位置,也可以在setImmediate中调用它。我还建议您查看WinJS调度程序API,它可以让您在UI线程上设置工作的优先级。

简而言之,了解 new WinJS.Promise WinJS.Promise.as 本身并不会创建异步行为,因为承诺本身只是一个呼叫约会&#34;结果将在以后交付&#34;与async毫无关系。