2015-09-25 67 views
1

編輯:重要提示這是使用jQuery 1.7.2,並沒有它不能從這個版本jQuery推遲承諾執行不按順序?

我是新來的承諾而改變,並試圖將其佈置我的頭。我試圖按順序執行一系列函數,等待它們在創建一些子視圖之前完成(這是在Backbone.js中)。這裏是我的代碼:

initialize: function() { 
    console.log('AppView::initialized!'); 
    var _this = this; 

    $.when(_this.processCookies()) 
     .then(_this.loadAdScripts()) 
     .then(_this.createChildViews()); 
}, 

processCookies: function() { 
    var def = $.Deferred(); 
    console.log('(1) PROCESS COOKIES'); 
    return def.resolve(); 
}, 


/** 
* Instantiates new instances of the child views. 
*/ 
createChildViews: function() { 
    var _this = this; 
    console.log('(4) CREATING CHILD VIEWS'); 
}, 

loadAdScripts: function() { 

    var _this = this, 
     def = $.Deferred(); 

    $.when(
     _this.insertScript({ 
      name: 'example1', 
      async: false, 
      src: '//www.example.com/script1.js', 
     }), 
     _this.insertScript({ 
      is_mobile: is_mobile, 
      name: 'example2', 
      async: true, 
      src: '//example.com/script2.js' 
     }) 
    ) 
    .done(function() { 
     console.log('(3) ALL SCRIPTS LOADED'); 
     def.resolve(); 
    }); 
}, 

insertScript: function (script) { 
    var def = $.Deferred(), 
     protocol = (document.location.protocol === 'https:' ? 'https:' : 'http:'); 

    // dont script 2 on mobile. 
    if (script.name === 'example2' && script.is_mobile) { 
     console.log('skipping script'); 
     return def.resolve(); 
    } 

    var promise = $.ajax({ 
     dataType: 'script', 
     cache: false, 
     async: script.async, 
     url: protocol + script.src, 
    }); 

    promise.done(function() { 
     console.log('(2) SINGLE SCRIPT LOADED'); 
     return def.resolve(); 
    }); 


}, 

因此,所需流量這裏是:

  1. processCookies()功能完成,
  2. 執行loadAdScripts功能 2A。 insertScript()火災,腳本1負載 2b。 insertScript()火災,腳本2加載
  3. 當這兩個腳本完成後,執行createChildViews函數。

所以,觀察console.log()佔位符中的代碼,我預計在我的控制檯上看到:

'(1) PROCESS COOKIES' 
'(2) SINGLE SCRIPT LOADED' 
'(2) SINGLE SCRIPT LOADED' 
'(3) ALL SCRIPTS LOADED' 
'(4) CREATING CHILD VIEWS' 

然而其實看到的是:

'(1) PROCESS COOKIES' 
'(3) ALL SCRIPTS LAODED' 
'(4) CREATING CHILD VIEWS' 
'(2) SINGLE SCRIPT LOADED' 
'(2) SINGLE SCRIPT LOADED' 

我的承諾有什麼問題,爲什麼他們沒有按照預期的順序執行?

+0

我不熟悉的承諾,但你在這裏使用Ajax調用,這就是異步!可能是您的電話無法正常工作的原因。您可以嘗試將成功的函數添加到ajax,一旦成功,請執行下一步。我在那裏看到其他函數調用。那些是異步的嗎?如果存在回調函數,您可能需要查看回調函數。 –

+0

@bravekido承諾也是異步的。 '$ .ajax'返回一個承諾。 OP完全瞭解異步問題,並試圖組織回調的順序 – charlietfl

+0

@bravekido是啊,他們是ajax調用,但我需要等待他們完成(或失敗),然後執行頁面的其餘部分,如charlieftl解釋。 – Prefix

回答

0
$.when(_this.processCookies()) 
     .then(_this.loadAdScripts()) 
     .then(_this.createChildViews()); 

似乎立即調用loadScripts()createChildViews(),而是試圖在.then(_this.loadAdScripts)引用的回調函數名。

return def.resolve()返回jQuery.Deferred()對象,而不是jQuery promise對象;嘗試在.resolve()之後添加.promise()以返回jQuery承諾對象。

jQuery.ajax()返回jQuery承諾對象;沒有必要建立新的jQuery $.Deferred()對象,可以返回$.ajax()

initialize: function() { 
    console.log('AppView::initialized!'); 
    var _this = this; 

    $.when(_this.processCookies()) 
     // reference function name, not invoked 
     .then(_this.loadAdScripts) 
     .then(_this.createChildViews); 
}, 

processCookies: function() { 
    // no asynchronous operations appear here, 
    // no need to include `$.Deferred()` or `.promise()` object 
    // var def = $.Deferred(); 
    console.log('(1) PROCESS COOKIES'); 
    // return jQuery promise object, not deferred object 
    // return def.resolve().promise(); 
}, 


/** 
* Instantiates new instances of the child views. 
*/ 
createChildViews: function() { 
    var _this = this; 
    console.log('(4) CREATING CHILD VIEWS'); 
}, 

loadAdScripts: function() { 

    //var _this = this, 
    // def = $.Deferred(); 

    return $.when(
     _this.insertScript({ 
      name: 'example1', 
      async: false, 
      src: '//www.example.com/script1.js', 
     }), 
     _this.insertScript({ 
      is_mobile: is_mobile, 
      name: 'example2', 
      async: true, 
      src: '//example.com/script2.js' 
     }) 
    ) 
    .done(function() { 
     console.log('(3) ALL SCRIPTS LOADED'); 
     // def.resolve(); 
    }); 
}, 

insertScript: function (script) { 
    // var def = $.Deferred(), 
     protocol = (document.location.protocol === 'https:' ? 'https:' : 'http:'); 

    // dont script 2 on mobile. 
    // if (script.name === 'example2' && script.is_mobile) { 
    // console.log('skipping script'); 
    // return def.resolve().promise(); 
    // } 

    var promise = script.name === 'example2' && script.is_mobile 
        ? $.when() 
        : $.ajax({ 
         dataType: 'script', 
         cache: false, 
         async: script.async, 
         url: protocol + script.src, 
        }); 

    promise.done(function() { 
     console.log('(2) SINGLE SCRIPT LOADED'); 
     // def.resolve(); 
    });  
}, 

編輯:這是使用jQuery 1.7.2,並沒有它不能 從這個版本改重要事項

編輯,更新

預期的順序m唉不可能使用jQuery 1.7.2版本,而無需修改源代碼。

看起來在使用jQuery版本1.8+時返回預期的順序,在更新deferred.then之後;見http://blog.jquery.com/2012/08/09/jquery-1-8-released/,http://bugs.jquery.com/ticket/11010

1.8。0

var dfd = { 
 
    initialize: function() { 
 
     console.log('AppView::initialized!'); 
 
     _this = dfd; 
 

 
     $.when(_this.processCookies()) 
 
     // reference function name, not invoked 
 
     .then(_this.loadAdScripts) 
 
     .then(_this.createChildViews); 
 
    }, 
 

 
    processCookies: function() { 
 
     // no asynchronous operations appear here, 
 
     // no need to include `$.Deferred()` or `.promise()` object 
 
     var def = $.Deferred(function (d) { 
 
      setTimeout(function() { 
 
       d.resolve('(1) PROCESS COOKIES') 
 
      }, Math.floor(Math.random() * 1000)); 
 
     }).promise(); 
 
     def.then(function (msg) { 
 
      console.log(msg); 
 
     }); 
 
     return def.promise() 
 
    }, 
 

 

 
    /** 
 
    * Instantiates new instances of the child views. 
 
    */ 
 
    createChildViews: function() { 
 
     _this = dfd; 
 
     console.log('(4) CREATING CHILD VIEWS'); 
 
    }, 
 

 
    loadAdScripts: function() { 
 
     _this = dfd; 
 
     return $.when.apply(_this, [_this.insertScript({ 
 
      name: 'example1', 
 
      async: false, 
 
      src: '//www.example.com/script1.js', 
 
     }), 
 
     _this.insertScript({ 
 
      is_mobile: true, 
 
      name: 'example2', 
 
      async: true, 
 
      src: '//example.com/script2.js' 
 
     })]).then(function() { 
 
      console.log('(3) ALL SCRIPTS LOADED'); 
 
     }) 
 
    }, 
 

 
    insertScript: function (script) { 
 
     // var def = $.Deferred(), 
 
     protocol = (document.location.protocol === 'https:' ? 'https:' : 'http:'); 
 

 
     // dont script 2 on mobile. 
 
     // if (script.name === 'example2' && script.is_mobile) { 
 
     // console.log('skipping script'); 
 
     // return def.resolve(); 
 
     // } 
 

 
     var promise = $.when(script.name === 'example2' && script.is_mobile ? $.Deferred(function (d) { 
 
      setTimeout(function() { 
 
       d.resolve('(2) skipping script', protocol + script.src) 
 
      }, Math.floor(Math.random() * 1000)) 
 
     }).promise() : $.Deferred(function (d) { 
 
      setTimeout(function() { 
 
       d.resolve('(2) SINGLE SCRIPT LOADED', protocol + script.src) 
 
      }, Math.floor(Math.random() * 1000)) 
 
     }).promise()) 
 
     
 
     return promise.then(function(msg) { 
 
      console.log(msg) 
 
     }); 
 
    } 
 
}; 
 

 
dfd.initialize();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>

1.72

var dfd = { 
 
    initialize: function() { 
 
     console.log('AppView::initialized!'); 
 
     _this = dfd; 
 

 
     $.when(_this.processCookies()) 
 
     // reference function name, not invoked 
 
     .then(_this.loadAdScripts) 
 
     .then(_this.createChildViews); 
 
    }, 
 

 
    processCookies: function() { 
 
     // no asynchronous operations appear here, 
 
     // no need to include `$.Deferred()` or `.promise()` object 
 
     var def = $.Deferred(function (d) { 
 
      setTimeout(function() { 
 
       d.resolve('(1) PROCESS COOKIES') 
 
      }, Math.floor(Math.random() * 1000)); 
 
     }).promise(); 
 
     def.then(function (msg) { 
 
      console.log(msg); 
 
     }); 
 
     return def.promise() 
 
    }, 
 

 

 
    /** 
 
    * Instantiates new instances of the child views. 
 
    */ 
 
    createChildViews: function() { 
 
     _this = dfd; 
 
     console.log('(4) CREATING CHILD VIEWS'); 
 
    }, 
 

 
    loadAdScripts: function() { 
 
     _this = dfd; 
 
     return $.when.apply(_this, [_this.insertScript({ 
 
      name: 'example1', 
 
      async: false, 
 
      src: '//www.example.com/script1.js', 
 
     }), 
 
     _this.insertScript({ 
 
      is_mobile: true, 
 
      name: 'example2', 
 
      async: true, 
 
      src: '//example.com/script2.js' 
 
     })]).then(function() { 
 
      console.log('(3) ALL SCRIPTS LOADED'); 
 
     }) 
 
    }, 
 

 
    insertScript: function (script) { 
 
     // var def = $.Deferred(), 
 
     protocol = (document.location.protocol === 'https:' ? 'https:' : 'http:'); 
 

 
     // dont script 2 on mobile. 
 
     // if (script.name === 'example2' && script.is_mobile) { 
 
     // console.log('skipping script'); 
 
     // return def.resolve(); 
 
     // } 
 

 
     var promise = $.when(script.name === 'example2' && script.is_mobile ? $.Deferred(function (d) { 
 
      setTimeout(function() { 
 
       d.resolve('(2) skipping script', protocol + script.src) 
 
      }, Math.floor(Math.random() * 1000)) 
 
     }).promise() : $.Deferred(function (d) { 
 
      setTimeout(function() { 
 
       d.resolve('(2) SINGLE SCRIPT LOADED', protocol + script.src) 
 
      }, Math.floor(Math.random() * 1000)) 
 
     }).promise()) 
 
     
 
     return promise.then(function(msg) { 
 
      console.log(msg) 
 
     }); 
 
    } 
 
}; 
 

 
dfd.initialize();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

+0

「downvote」的描述? – guest271314

+2

我沒有downvote,但...答案描述?有什麼不同? OP只是調用函數並將結果傳遞給'.then()'?不要讓我們逐行比較你的代碼和原始代碼。 – nnnnnn

+0

我也沒有downvote,但描述會很好:) – Prefix