简体   繁体   English

如何在javascript中同步调用一组函数

[英]How to synchronously call a set of functions in javascript

I am working on a javascript project that needs to get some data and process it, but I am having trouble with the asynchronous nature of JavaScript. 我正在开发一个需要获取一些数据并处理它的javascript项目,但我遇到了JavaScript异步性质的问题。 What I want to be able to do is something like the following. 我想要做的是如下所示。

//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();
}

Here I want each function to wait for completion before going on to the next call, as I am running into the situation where the program attempts to validate the data before it has been retrieved. 在这里,我希望每个函数在继续下一次调用之前等待完成,因为我遇到程序在检索之前尝试验证数据的情况。 However, I also want to be able to return a value from these functions for testing, so I can't have these functions return a boolean value to check completion. 但是,我还希望能够从这些函数返回一个值进行测试,所以我不能让这些函数返回一个布尔值来检查完成。 How can I make javascript wait on the function to run to completion before moving on to the next call? 在进入下一个调用之前,如何让javascript等待函数运行完成?

Use promises: 使用承诺:

 //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); }) 

Not only are they easy to grasp, it makes total sense from a code readability stand point. 它们不仅容易掌握,而且从代码可读性的角度来看也很有意义。 Read more about them here . 在这里阅读更多相关信息。 If you are in a browser environment, I recommend this polyfill. 如果您在浏览器环境中,我建议使用 polyfill。

The code you've quoted will run synchronously. 您引用的代码将同步运行。 JavaScript function calls are synchronous. JavaScript函数调用是同步的。

So I'm going to assume that getData , parseData , and/or validate involve asynchronous operations (such as using ajax in a browser, or readFile in NodeJS). 所以我假设getDataparseData和/或validate涉及异步操作(例如在浏览器中使用ajax,或在parseData中使用readFile )。 If so, you basically have two options, both of which involve callbacks . 如果是这样,你基本上有两个选项,两个选项都涉及回调

The first is to just have those functions accept callbacks they'll call when done, for instance: 第一个是让这些函数接受它们在完成时调用的回调,例如:

function getData(callback) {
    someAsyncOperation(function() {
        // Async is done now, call the callback with the data
        callback(/*...some data...*/);
    });
}

you'd use that like this: 你会像这样使用它:

getData(function(data) {
    // Got the data, do the next thing
});

The problem with callbacks is that they're hard to compose and have fairly brittle semantics. 回调的问题在于它们很难编写并且具有相当脆弱的语义。 So promises were invented to give them better semantics. 因此发明了承诺以给予它们更好的语义。 In ES2015 (aka "ES6") or with a decent promises library, that would look something like this: 在ES2015(又名“ES6”)或一个体面的promises库中,它看起来像这样:

function getData(callback) {
    return someAsyncOperation();
}

or if someAsyncOperation is not promise-enabled, then: 或者如果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
        });
    });
}

Doesn't seem to do much for you, but one of the key things is composability ; 似乎没有为你做太多,但其中一个关键的事情是可组合性 ; your final function ends up looking like this: 你的最终功能最终看起来像这样:

function runner() {
    return getData()
        .then(parseData) // Yes, there really aren't () on parseData...
        .then(validate); // ...or validate
}

usage: 用法:

runner()
    .then(function(result) {
         // It worked, use the result
    })
    .catch(function(error) {
         // It failed
    });

Here's an example; 这是一个例子; it will only work on a fairly recent browser that supports Promise and ES2015 arrow functions, because I was lazy and wrote it with arrow functions and didn't include a Promise lib: 它只适用于支持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) 

You should change each function to return a Promise , which will allow your final function to become: 您应该更改每个函数以返回Promise ,这将允许您的最终函数变为:

function runner() {
    return Promise.try(getData).then(parseData).then(validate);
}

To do that, the body of each function should be wrapped in a new promise, like: 要做到这一点,每个函数的主体应该包含在一个新的承诺中,如:

function getData() {
  return new Promise(function (res, rej) {
    var req = new AjaxRequest(...); // make the request
    req.onSuccess = function (data) {
      res(data);
    };
  });
}

This is a very cursory example of how promises might work. 这是承诺如何运作的一个非常粗略的例子。 For more reading, check out: 欲了解更多信息,请查看:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM