2017-03-16 96 views
1

這裏是我的情況:異步函數內部少輝

fetchData(foo).then(result => { 
    return new Promise((resolve, reject) => { 
     setTimeout(() => { 
      resolve(result + bar); 
     }, 0) 
    }); 
}).then(result => { 
    return new Promise((resolve, reject) => { 
     setTimeout(() => { 
      resolve(result + woo); 
     }, 0) 
    }); 
}).then(result => { 
    setTimeout(() => { 
     doSomething(result); 
    }, 0) 
}); 

其中每個setTimeout的是使用回調格局不同的異步操作。

這實在是不好受來包裝一個承諾內的各功能,我覺得自己的代碼應該看起來更像是這樣的:

fetchData(foo).then(result => { 
    setTimeout(() => { 
     return result + bar; 
    }, 0) 
}).then(result => { 
    setTimeout(() => { 
     return result + woo; 
    }, 0) 
}).then(result => { 
    setTimeout(() => { 
     doSomething(result); 
    }, 0) 
}); 

顯然,這是行不通的。

我是否使用Promises?我是否真的必須在承諾中包含所有現有的異步函數?

編輯:

其實我知道我的例子也並非完全reprensentative我的情況,我沒有說清楚,在我的例子中的setTimeout是爲了reprensent EN異步操作。這種情況更能代表我的情況:

fetchData(foo).then(result => { 
    return new Promise((resolve, reject) => { 
     asyncOperation(result, operationResult => { 
      resolve(operationResult); 
     }, 0) 
    }); 
}).then(result => { 
    return new Promise((resolve, reject) => { 
     otherAsyncOperation(result, otherAsyncResult => { 
      resolve(otherAsyncResult); 
     }, 0) 
    }); 
}).then(result => { 
     doSomething(result); 
}); 
+0

如果您不想使用諾言,您可以使用自定義事件。這個事件將被觸發每個檢測變化! (https://www.sitepoint.com/javascript-custom-events/)....但爲什麼你不喜歡使用諾言? –

+1

有像''pify'](https://github.com/sindresorhus/pify)這樣的模塊可以幫助您提供現有的基於回調的異步函數。此外,合理數量的包爲其異步函數提供_both_承諾和回調支持(當您不傳遞迴調函數時,它們會返回一個承諾)。但我不能說這是否適用於你的情況。 – robertklep

+0

^^是或'bluebird'非常簡單,其行爲與原生Promise類似,但對節點樣式回調更友好。 [鏈接](http://bluebirdjs.com/docs/api/promise.fromcallback.html) – user3821538

回答

3

我使用Promises嗎?我是否真的必須在承諾中包含所有現有的異步函數?

是的。是。

我覺得代碼應該看起來更像這個

不,它不應該。它,而應該是這樣的:

function promiseOperation(result) { 
    return new Promise((resolve, reject) => { 
     asyncOperation(result, resolve, 0) 
    }); 
} 
function otherPromiseOperation(result) { 
    return new Promise((resolve, reject) => { 
     otherAsyncOperation(result, resolve, 0) 
    }); 
} 

fetchData(foo).then(promiseOperation).then(otherPromiseOperation).then(doSomething); 

這實在是不好受包裹承諾

嘛內的各功能,不要反覆它每一次寫出來的。你可以將這個包裝抽象成一個函數!

function promisify(fn) { 
    return value => new Promise(resolve => { 
     fn(value, resolve, 0) 
    }); 
} 
const promiseOperation = promisify(asyncOperation); 
const otherPromiseOperation = promisify(otherAsyncOperation); 
fetchData(foo).then(promiseOperation).then(otherPromiseOperation).then(doSomething); 

注意,最有希望的庫都配備了這樣一個包含功能promisification,讓你的整個代碼減少了這三條線。

0

您使用的是承諾權。剛上的代碼的第一個片段小記:

... 
}).then(result => { 
    setTimeout(() => { 
     doSomething(result); 
    }, 0) 
}); 

這是正確的,如果你需要簡單地做一個異步操作,而無需返回到fetchData的來電:你是不是從最後then()回調返回一個承諾最後的異步操作的值。如果您需要返回這個值,你需要轉換爲過承諾此操作:

fetchData(foo).then(result => { 
    return new Promise((resolve, reject) => { 
     setTimeout(() => { 
      resolve(result + bar); 
     }, 0) 
    }); 
}).then(result => { 
    return new Promise((resolve, reject) => { 
     setTimeout(() => { 
      resolve(result + woo); 
     }, 0) 
    }); 
}).then(result => { 
    return new Promise((resolve, reject) => { 
     setTimeout(() => { 
      resolve(doSomething(result)); 
     }, 0) 
    }); 
}); 

在這裏,我想doSomething同步函數返回一個值。

這麼說,如果你想減少創建承諾的噪音每次包setTimeout,你可以創建一個效用函數setTimeoutWithPromise

function setTimeoutWithPromise(operation, millisec) { 
    return new Promise((resolve, reject) => { 
     setTimeout(() => { 
      resolve(operation()); 
     }, millisec) 
    }); 
} 

和清理你的代碼:

fetchData(foo) 
    .then(result => setTimeoutWithPromise(() => result + bar, 0)) 
    .then(result => setTimeoutWithPromise(() => result + woo, 0)) 
    .then(result => setTimeoutWithPromise(() => doSomething(result), 0));