在 JavaScript 中强制代码按顺序 运行

Forcing code to run sequentially in JavaScript

Angular.jsSocket.io 应用程序中,我想在通过 Socket.io 发送图像之前显示加载。我写这段代码:

当按钮单击此代码 运行s 时,首先我想要 运行 startLoading 功能,然后我想发送图像:

$scope.startLoading(function(){
      $scope.socket.emit('sendImg', {
            data: $scope.newImg,
      });
});

这是我的 startLoading 函数:

$scope.startLoading = function (callback) {
    //DO SOME STUFF LIKE ENABLING LOADING ANIMATION
    $scope.animation =true; //binded to UI
    $scope.errors = false; //binded to UI

    callback(); //it seems this code runs before above lines
};

但似乎在前两行之前 callback() 行 运行s,因此,我的加载出现在将图像发送到服务器之后!为什么?我将回调线更改为这样的超时并且它工作正常但这是一个好的解决方案吗?我不认为!我必须为标准代码做什么?

$scope.startLoading = function (callback) {
    //DO SOME STUFF LIKE ENABLING LOADING ANIMATION
    $scope.animation =true; //binded to UI
    $scope.errors = false; //binded to UI

    $timeout(function(){callback();}, 1000);
};

实际上,代码 运行s 顺序调用回调和发送图像冻结页面,因此,我的加载出现在冻结结束后。但我需要在冻结之前开始加载

您的代码确实按顺序 运行,但前两行不会立即更改 UI。

当您为作用域变量赋值时,就是变量赋值。它不会触发任何事件。 Angular 只会在稍后评估绑定并找到更改时更新 UI。所以这是发生了什么:

$scope.startLoading = function (callback) {

    // Presumably this is called from some event from Angular, 
    // so all this is run in an $apply, in an Angular "context".
    // But this is still "plain" javascript, so the next two lines
    // are just plain variable assignments.

    $scope.animation =true;
    $scope.errors = false;

    callback();  // This function does its thing, then returns

    // When this function returns, Angular will evaluate all of its
    // bindings, will find that the above values have changed,
    // and will update the DOM.
};

有关详细信息,请参阅 dev guide 中的 "Integration with the browser event loop" 部分。

您想要的是确保 DOM 在 您的回调 运行 之前更新 。我认为为此使用 $timeout 没有错。 可能有 better/nicer 方法,但我还没有找到...

所以会变成这样:

$scope.startLoading = function (callback) {
    $scope.animation =true;  // at this point, these are just
    $scope.errors = false;   // plain variable assignments

    $timeout(callback);  // schedule callback to run later

    // After this returns, Angular will evaluate its bindings,
    // and update the DOM, so if $scope.animation and $scope.errors
    // are bound to something, they can trigger some visible change.

    // callback will be called in the next $digest cycle, so _after_
    // the DOM has been updated
};

(如果你只想在下一个"tick"中运行超时,则无需指定超时值。另外,不需要包装回调,它可以直接传递给$timeout.)

希望对您有所帮助!