如何在javascript中同步调用一组函数
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();
}
这里我希望每个函数在继续下一个调用之前等待完成,因为我 运行 进入程序尝试在检索数据之前验证数据的情况。但是,我也希望能够从这些函数中 return 一个值来进行测试,所以我不能让这些函数 return 一个布尔值来检查是否完成。如何让 javascript 等待函数 运行 完成后再继续下一个调用?
您应该将每个函数更改为 return a 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);
};
});
}
这是一个非常粗略的例子,说明了 promises 是如何工作的。如需更多阅读,请查看:
- 2ality 的精彩博文:part 1 and part 2
- bluebird 关于 why promises
的文档
- mdn 关于 JS'
Promise
class 的文档
使用承诺:
//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);
})
它们不仅易于掌握,而且从代码可读性的角度来看也很有意义。阅读更多关于它们的信息 here. If you are in a browser environment, I recommend this polyfill。
您引用的代码将运行同步。 JavaScript 函数调用是同步的。
所以我假设 getData
、parseData
、and/or validate
涉及 异步 操作(例如如在浏览器中使用 ajax,或在 NodeJS 中使用 readFile
)。如果是这样,您基本上有两个选择,都涉及 callbacks.
首先是让那些函数接受它们在完成时调用的回调,例如:
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
});
回调的问题在于它们难以组合并且具有相当脆弱的语义。所以发明了 promises 来赋予它们更好的语义。在 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)
我正在开展一个 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();
}
这里我希望每个函数在继续下一个调用之前等待完成,因为我 运行 进入程序尝试在检索数据之前验证数据的情况。但是,我也希望能够从这些函数中 return 一个值来进行测试,所以我不能让这些函数 return 一个布尔值来检查是否完成。如何让 javascript 等待函数 运行 完成后再继续下一个调用?
您应该将每个函数更改为 return a 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);
};
});
}
这是一个非常粗略的例子,说明了 promises 是如何工作的。如需更多阅读,请查看:
- 2ality 的精彩博文:part 1 and part 2
- bluebird 关于 why promises 的文档
- mdn 关于 JS'
Promise
class 的文档
使用承诺:
//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);
})
它们不仅易于掌握,而且从代码可读性的角度来看也很有意义。阅读更多关于它们的信息 here. If you are in a browser environment, I recommend this polyfill。
您引用的代码将运行同步。 JavaScript 函数调用是同步的。
所以我假设 getData
、parseData
、and/or validate
涉及 异步 操作(例如如在浏览器中使用 ajax,或在 NodeJS 中使用 readFile
)。如果是这样,您基本上有两个选择,都涉及 callbacks.
首先是让那些函数接受它们在完成时调用的回调,例如:
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
});
回调的问题在于它们难以组合并且具有相当脆弱的语义。所以发明了 promises 来赋予它们更好的语义。在 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)