2013-06-20 30 views
15

tôi muốn làm một cái gì đó như sau:Tôi có thể hứa hẹn đồng bộ trong thư viện JavaScript Q không?

delay(2500) 
    .then(function() { console.log("Step 1 done") }) 
    .then(delay(7500)) 
    .then(function() { console.log("Step 2 done") }); 

Vì vậy, thực hiện chậm trễ đã được chứng minh nhiều lần trước đây:

function delay(ms) { 
    var deferred = Q.defer(); 
    setTimeout(deferred.resolve, ms); 
    return deferred.promise; 
} 

Nhưng nếu tôi chạy ở trên trong Node.js tôi nhận được:

... delay of 2500ms 
Step 1 done 
Step 2 done 
... delay of ~7500ms 

chứ không phải là những gì tôi mong đợi để xem:

... delay of 2500ms 
Step 1 done 
... delay of 7500ms 
Step 2 done 

Trong các ví dụ được cung cấp trên https://github.com/kriskowal/q/wiki/Examples-Gallery Tôi không thể tìm thấy bất kỳ ví dụ nào về chức năng đồng bộ (hàm trả về giá trị mà không có bất kỳ callback nào liên quan) bị xích với các hàm lời hứa.

Bất kỳ ý tưởng nào về cách kết hợp các hành động đồng bộ với lời hứa không đồng bộ?

Tôi đã thử:

function synchronousPromise() { 
    var deferred = Q.defer(); 
    console.log("Synchronous function call"); 
    deferred.resolve(); 
    return deferred.promise; 
} 

delay(2500) 
    .then(function(){synchronousPromise()}) 
    .then(function(){delay(7500)}) 
    .then(function(){synchronousPromise()}); 

Và kết quả đầu ra này:

... delay of 2500ms 
Time now is 2013-06-20 
Time now is 2013-06-20 
... delay of 7500ms 

.. vẫn không phải những gì tôi đang cố gắng để đạt được.

+1

Trong ví dụ đầu tiên của bạn, bạn đã thử '.then (function() {return delay (7500);})' thay vì '.then (delay (7500))'? –

+0

@FelixKling hoạt động cho ví dụ đầu tiên và thứ hai! Làm cho câu trả lời của bạn và tôi sẽ chấp nhận. –

+0

Bây giờ bạn có thể đạt được điều này mà không cần phải xác định thời gian trễ kiểm tra [answer] của tôi [http://stackoverflow.com/questions/17213297/can-i-make-a-synchronous-promise-in-the-javascript-q -library/33298652 # answer-33298652). –

Trả lời

13

Nếu bạn muốn chuỗi các cuộc gọi lại, bạn phải trả về một đối tượng lời hứa mới từ một trong các cuộc gọi lại. Trong ví dụ đầu tiên của bạn, bạn viết

.then(delay(7500)) 

có nghĩa là bạn đang chuyển đối tượng lời hứa đến .then, không phải chức năng. Theo số Promise/A+ proposal (mà Q theo sau), tất cả các đối số phi hàm phải được bỏ qua. Vì vậy, về cơ bản nó giống như nếu bạn chỉ cần viết:

delay(2500) 
    .then(function() { console.log("Step 1 done") }) 
    .then(function() { console.log("Step 2 done") }); 

Thay vào đó, vượt qua chức năng trong đó kêu gọi delay và trả về đối tượng lời hứa:

delay(2500) 
    .then(function() { console.log("Step 1 done"); }) 
    .then(function() { return delay(7500); }) 
    .then(function() { console.log("Step 2 done"); }); 

Bây giờ gọi lại cuối cùng sẽ chỉ được gọi một lần lời hứa đối tượng được trả về bởi delay trong lần gọi lại thứ hai được giải quyết.

3

Google mang tôi đến đây trong khi làm việc thông qua một vấn đề tương tự (nhưng sử dụng Kris Kowal của Q), tôi đã kết thúc với một khuôn khổ rất nhỏ cho phép bạn làm như sau:

var chain = [ 
    doNext(delay, 2500), 
    doNext(console.log, "Step 1 done"), 
    doNext(delay, 7500), 
    doNext(console.log, "Step 2 done") 
]; 

doInOrder(chain); 

Khung chỉ là 12 dòng , và có lẽ có thể được điều chỉnh cho các thư viện lời hứa khác:

var Q = require('q'); 

function doNext(fn /* , arguments */){ 
    var args = Array.prototype.splice.call(arguments, 1); 
    return function(prevRetVal){ 
    // For my needs I didn't need the results from previous fns 
    return fn.apply(null, args) 
    } 
} 

function doInOrder(doNexters, init){ 
    return doNexters.reduce(Q.when, init); 
} 
0

Nếu bạn làm việc với Babel hoặc đánh máy bạn có thể sử dụng ES6 Generators:

'use strict'; 

    let asyncTask =() => 
    new Promise(resolve => { 
     let delay = Math.floor(Math.random() * 1000); 

     setTimeout(function() { 
     resolve(delay); 
     }, delay); 
    }); 

    let makeMeLookSync = fn => { 
    let iterator = fn(); 
    let loop = result => { 
     !result.done && result.value.then(res => 
     loop(iterator.next(res))); 
    }; 

    loop(iterator.next()); 
    }; 

    makeMeLookSync(function*() { 
    let result = yield asyncTask(); 

    console.log(result); 
    }); 
Các vấn đề liên quan