如何在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 等待函数运行完成?

原文由 Nick P 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 507
2 个回答

使用承诺:

 //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。

原文由 m-a-r-c-e-l-i-n-o 发布,翻译遵循 CC BY-SA 3.0 许可协议

您引用的代码将同步运行。 JavaScript 函数调用是同步的。

所以我要假设 getData readFile parseData 和/或 validate 涉及 异步 操作(例如使用浏览器,或 ajax- --- 在 NodeJS 中)。如果是这样,您基本上有两个选择,都涉及 _回调_。

第一种是让那些函数接受它们在完成时调用的回调,例如:

 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 未启用承诺,则:

 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)

原文由 T.J. Crowder 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题