我如何从函数 foo 返回一个无同步请求的答案/结果?

我正在尝试从呼叫返回的值,以及将结果分配到函数内部的本地变量,并返回其中一个,但没有这些方式实际上返回答案 - 他们都返回不确定的或无论变量结果的初始值是什么。

一个不同步函数的例子,接受召回(使用 jQuery 的 ajax 函数):

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- I tried that one as well
        }
    });

    return result; // It always returns `undefined`
}

使用 Node.js 的例子:

function foo() {
    var result;

    fs.readFile("path/to/file", function(err, data) {
        result = data;
        // return data; // <- I tried that one as well
    });

    return result; // It always returns `undefined`
}

例如,使用那时承诺的区块:

function foo() {
    var result;

    fetch(url).then(function(response) {
        result = response;
        // return response; // <- I tried that one as well
    });

    return result; // It always returns `undefined`
}

当前回答

另一个解决方案是通过序列执行器 nsynjs 执行代码。

nsynjs 将连续评估所有承诺,并将承诺结果列入数据属性:

函数同步Code() { var getURL = 函数(url) { return window.fetch(url).data.text().data; }; var url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js'; console.log('收到的比特:',getURL(url).length); }; nsynjs.run(同步Code,{},函数(){ console.log('同步Code done'); }; <script src="https://rawgit.com/amaksr/

如果基本功能不承诺

步骤 1 将函数与呼叫回归到 nsynjs-aware 插槽中(如果它有一个有前途的版本,你可以错过这个步骤):

var ajaxGet = function (ctx,url) {
    var res = {};
    var ex;
    $.ajax(url)
    .done(function (data) {
        res.data = data;
    })
    .fail(function(e) {
        ex = e;
    })
    .always(function() {
        ctx.resume(ex);
    });
    return res;
};
ajaxGet.nsynjsHasCallback = true;

function process() {
    console.log('got data:', ajaxGet(nsynjsCtx, "data/file1.json").data);
}

步骤3:通过 nsynjs 以同步方式运行函数:

nsynjs.run(process,this,function () {
    console.log("synchronous function finished");
});

Nsynjs 将逐步评估所有运营商和表达式,如果某些缓慢功能的结果不准备好,则停止执行。

这里有更多的例子。

其他回答

问题是:

我如何从无同步通话中返回答案?

可以被解释为:

如何让同步代码看起来同步?

解决方案将是避免呼叫,并使用一个组合的承诺和async/await。

我想举一个例子给一个Ajax请求。

(虽然它可以用JavaScript写作,但我宁愿用Python写作,并用Transcrypt编写到JavaScript。

首先,让我们启用 jQuery 使用,以便有 $ 作为 S 可用:

__pragma__ ('alias', 'S', '$')

设置一个函数返回承诺,在这种情况下,一个Ajax呼叫:

def read(url: str):
    deferred = S.Deferred()
    S.ajax({'type': "POST", 'url': url, 'data': { },
        'success': lambda d: deferred.resolve(d),
        'error': lambda e: deferred.reject(e)
    })
    return deferred.promise()

使用非同步代码,就好像它是同步的:

async def readALot():
    try:
        result1 = await read("url_1")
        result2 = await read("url_2")
    except Exception:
        console.warn("Reading a lot failed")

function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

findItem(function(item) {
    // Do something with the item
});
doSomethingElse();



重要: 您只能在一个 async 函数或 JavaScript 模块中使用等待。 顶级等待不支持模块之外,因此您可能需要创建一个 async IIFE (即时邀请函数表达) 以启动一个 async 背景,如果不使用模块。

// Using 'superagent' which will return a promise.
var superagent = require('superagent')

// This is isn't declared as `async` because it already returns a promise
function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}

async function getAllBooks() {
  try {
    // GET a list of book IDs of the current user
    var bookIDs = await superagent.get('/user/books');
    // wait for 3 seconds (just for the sake of this example)
    await delay();
    // GET information about each book
    return superagent.get('/books/ids='+JSON.stringify(bookIDs));
  } catch(error) {
    // If any of the awaited promises was rejected, this catch block
    // would catch the rejection reason
    return null;
  }
}

// Start an IIFE to use `await` at the top level
(async function(){
  let books = await getAllBooks();
  console.log(books);
})();


var result = foo();
// Code that depends on 'result'

foo(function(result) {
    // Code that depends on 'result'
});

function myCallback(result) {
    // Code that depends on 'result'
}

foo(myCallback);

function foo(callback) {
    $.ajax({
        // ...
        success: callback
    });
}

function foo(callback) {
    $.ajax({
        // ...
        success: function(response) {
            // For example, filter the response
            callback(filtered_response);
        }
    });
}


更多关于承诺的信息: HTML5 Rocks - JavaScript 承诺。

副注:jQuery的废弃物品

function ajax() {
    return $.ajax(...);
}

ajax().done(function(result) {
    // Code depending on result
}).fail(function() {
    // An error occurred
});

function checkPassword() {
    return $.ajax({
        url: '/password',
        data: {
            username: $('#username').val(),
            password: $('#password').val()
        },
        type: 'POST',
        dataType: 'json'
    });
}

if (checkPassword()) {
    // Tell the user they're logged in
}

但修正很容易:

checkPassword()
.done(function(r) {
    if (r) {
        // Tell the user they're logged in
    } else {
        // Tell the user their password was bad
    }
})
.fail(function(x) {
    // Tell the user something bad happened
});

不推荐:同步“Ajax”通话

正如我提到的那样,一些(!)无同步操作有同步对手,我不支持它们的使用,但为了完整性,这里是如何进行同步呼叫:

没有 jQuery

jQuery

function foo() {
    var jqXHR = $.ajax({
        //...
        async: false
    });
    return jqXHR.responseText;
}

如果您使用任何其他 jQuery Ajax 方法,如 $.get, $.getJSON 等,您必须将其更改为 $.ajax (因为您只能将配置参数转移到 $.ajax)。

在 foo() 成功中使用 callback() 函数. 以此方式尝试它. 它很简单,很容易理解。

var lat = "";
var lon = "";

function callback(data) {
    lat = data.lat;
    lon = data.lon;
}

function getLoc() {
    var url = "http://ip-api.com/json"
    $.getJSON(url, function(data) {
        callback(data);
    });
}

getLoc();

使用 ES2017 您应该将此作为功能声明。

async function foo() {
  var response = await $.ajax({url: '...'})
  return response;
}

这样执行它。

(async function() {
  try {
    var result = await foo()
    console.log(result)
  } catch (e) {}
})()

或承诺的合成。

foo().then(response => {
  console.log(response)

}).catch(error => {
  console.log(error)

})

Stack Snippet 显示上面的代码。

// 函数声明: async 函数 foo() { var 回复 = 等待 $.ajax({ url: 'https://jsonplaceholder.typicode.com/todos/1' }) 返回回回复; } // 执行此类: (async 函数() { 尝试 { var 结果 = 等待 foo() console.log(result) } 捕捉(e) {} }() // 或使用 承诺 合成: foo().then(回复 => { console.log(response) }。

我会用可怕的看起来,手拍的漫画来回答,第二张图像是为什么结果在您的代码示例中无法定义的原因。

此分類上一篇