簡體   English   中英

如何在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();
}

在這里,我希望每個函數在繼續下一次調用之前等待完成,因為我遇到程序在檢索之前嘗試驗證數據的情況。 但是,我還希望能夠從這些函數返回一個值進行測試,所以我不能讓這些函數返回一個布爾值來檢查完成。 在進入下一個調用之前,如何讓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函數調用是同步的。

所以我假設getDataparseData和/或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);
    };
  });
}

這是承諾如何運作的一個非常粗略的例子。 欲了解更多信息,請查看:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM