[英]How to synchronously call a set of functions in javascript
我正在開發一個需要獲取一些數據並處理它的javascript項目,但我遇到了JavaScript異步性質的問題。 我想要做的是如下所示。
//The set of functions that I want to call in order
function getData() {
//gets the data
}
function parseData() {
//does some stuff with the data
}
function validate() {
//validates the data
}
//The function that orchestrates these calls
function runner() {
getData();
parseData();
validate();
}
在這里,我希望每個函數在繼續下一次調用之前等待完成,因為我遇到程序在檢索之前嘗試驗證數據的情況。 但是,我還希望能夠從這些函數返回一個值進行測試,所以我不能讓這些函數返回一個布爾值來檢查完成。 在進入下一個調用之前,如何讓javascript等待函數運行完成?
使用承諾:
//The set of functions that I want to call in order function getData(initialData) { //gets the data return new Promise(function (resolve, reject) { resolve('Hello World!') }) } function parseData(dataFromGetDataFunction) { //does some stuff with the data return new Promise(function (resolve, reject) { resolve('Hello World!') }) } function validate(dataFromParseDataFunction) { //validates the data return new Promise(function (resolve, reject) { resolve('Hello World!') }) } //The function that orchestrates these calls function runner(initialData) { return getData(initialData) .then(parseData) .then(validate) } runner('Hello World!').then(function (dataFromValidateFunction) { console.log(dataFromValidateFunction); })
它們不僅容易掌握,而且從代碼可讀性的角度來看也很有意義。 在這里閱讀更多相關信息。 如果您在瀏覽器環境中,我建議使用此 polyfill。
您引用的代碼將同步運行。 JavaScript函數調用是同步的。
所以我假設getData
, parseData
和/或validate
涉及異步操作(例如在瀏覽器中使用ajax,或在parseData
中使用readFile
)。 如果是這樣,你基本上有兩個選項,兩個選項都涉及回調 。
第一個是讓這些函數接受它們在完成時調用的回調,例如:
function getData(callback) {
someAsyncOperation(function() {
// Async is done now, call the callback with the data
callback(/*...some data...*/);
});
}
你會像這樣使用它:
getData(function(data) {
// Got the data, do the next thing
});
回調的問題在於它們很難編寫並且具有相當脆弱的語義。 因此發明了承諾以給予它們更好的語義。 在ES2015(又名“ES6”)或一個體面的promises庫中,它看起來像這樣:
function getData(callback) {
return someAsyncOperation();
}
或者如果someAsyncOperation
未啟用promise,則:
function getData(callback) {
return new Promise(function(resolve, reject) {
someAsyncOperation(function() {
// Async is done now, call the callback with the data
resolve(/*...some data...*/);
// Or if it failed, call `reject` instead
});
});
}
似乎沒有為你做太多,但其中一個關鍵的事情是可組合性 ; 你的最終功能最終看起來像這樣:
function runner() {
return getData()
.then(parseData) // Yes, there really aren't () on parseData...
.then(validate); // ...or validate
}
用法:
runner()
.then(function(result) {
// It worked, use the result
})
.catch(function(error) {
// It failed
});
這是一個例子; 它只適用於支持Promise
和ES2015箭頭函數的最新瀏覽器,因為我很懶,用箭頭函數編寫它並且沒有包含Promise庫:
"use strict"; function getData() { // Return a promise return new Promise((resolve, reject) => { setTimeout(() => { // Let's fail a third of the time if (Math.random() < 0.33) { reject("getData failed"); } else { resolve('{"msg":"This is the message"}'); } }, Math.random() * 100); }); } function parseData(data) { // Note that this function is synchronous return JSON.parse(data); } function validate(data) { // Let's assume validation is synchronous too // Let's also assume it fails half the time if (!data || !data.msg || Math.random() < 0.5) { throw new Error("validation failed"); } // It's fine return data; } function runner() { return getData() .then(parseData) .then(validate); } document.getElementById("the-button").addEventListener( "click", function() { runner() .then(data => { console.log("All good! msg: " + data.msg); }) .catch(error => { console.error("Failed: ", error && error.message || error); }); }, false );
<input type="button" id="the-button" value="Click to test"> (you can test more than once)
您應該更改每個函數以返回Promise
,這將允許您的最終函數變為:
function runner() {
return Promise.try(getData).then(parseData).then(validate);
}
要做到這一點,每個函數的主體應該包含在一個新的承諾中,如:
function getData() {
return new Promise(function (res, rej) {
var req = new AjaxRequest(...); // make the request
req.onSuccess = function (data) {
res(data);
};
});
}
這是承諾如何運作的一個非常粗略的例子。 欲了解更多信息,請查看:
Promise
類
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.