我如何从函数 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`
}

当前回答

你的代码应该是沿着这条线的一点:

function foo() {
    var data;
    // Or $.get(...).then, or request(...).then, or query(...).then
    fetch("/echo/json").then(function(response){
        data = response.json();
    });
    return data;
}

var result = foo(); // 'result' is always undefined no matter what.


当我们打电话给一个承诺并从中返回一些东西时,我们会得到处理的价值的承诺;如果我们返回另一个承诺,我们会得到惊人的东西,但让我们抓住我们的马。

function delay(ms){ // Takes amount of milliseconds
    // Returns a new promise
    return new Promise(function(resolve, reject){
        setTimeout(function(){ // When the time is up,
            resolve(); // change the promise to the fulfilled state
        }, ms);
    });
}

基本上,而不是返回一个值,我们不能因为竞争模式 - 我们正在返回一个值,我们可以与它无缝。

function foo() {
    // RETURN the promise
    return fetch("/echo/json").then(function(response){
        return response.json(); // Process it inside the `then`
    });
}

foo().then(function(response){
    // Access the value inside the `then`
})

function* foo(){ // Notice the star. This is ES6, so new browsers, Nodes.js, and io.js only
    yield 1;
    yield 2;
    while(true) yield 3;
}

var foo = coroutine(function*(){
    var data = yield fetch("/echo/json"); // Notice the yield
    // The code here only executes _after_ the request is done
    return data.json(); // 'data' is defined
});

var main = coroutine(function*(){
   var bar = yield foo(); // Wait our earlier coroutine. It returns a promise
   // The server call is done here, and the code below executes when done
   var baz = yield fetch("/api/users/" + bar.userid); // Depends on foo's result
   console.log(baz); // Runs after both requests are done
});
main();

2016年(ES7)

在ES7中,这一点进一步标准化了,现在有几个建议,但在所有这些建议中,你可以等待承诺,这只是ES6提议的“糖”(尼克合成)通过添加同步并等待关键词。

async function foo(){
    var data = await fetch("/echo/json"); // Notice the await
    // code here only executes _after_ the request is done
    return data.json(); // 'data' is defined
}

其他回答

另一种方法是从无同步函数中返回值,是通过将结果从无同步函数中存储的对象。

下面是相同的例子:

var async = require("async");

// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
    // some asynchronous operation
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;
            _callback();
        }
    });
});

async.parallel(asyncTasks, function(){
    // result is available after performing asynchronous operation
    console.log(result)
    console.log('Done');
});

我正在使用结果对象来存储在无同步操作期间的值,这使得结果即使在无同步工作后也可用。

我使用这个方法很多,我会感兴趣知道这个方法有多好运作,在那里通过连续模块将结果传输回来。

你的代码应该是沿着这条线的一点:

function foo() {
    var data;
    // Or $.get(...).then, or request(...).then, or query(...).then
    fetch("/echo/json").then(function(response){
        data = response.json();
    });
    return data;
}

var result = foo(); // 'result' is always undefined no matter what.


当我们打电话给一个承诺并从中返回一些东西时,我们会得到处理的价值的承诺;如果我们返回另一个承诺,我们会得到惊人的东西,但让我们抓住我们的马。

function delay(ms){ // Takes amount of milliseconds
    // Returns a new promise
    return new Promise(function(resolve, reject){
        setTimeout(function(){ // When the time is up,
            resolve(); // change the promise to the fulfilled state
        }, ms);
    });
}

基本上,而不是返回一个值,我们不能因为竞争模式 - 我们正在返回一个值,我们可以与它无缝。

function foo() {
    // RETURN the promise
    return fetch("/echo/json").then(function(response){
        return response.json(); // Process it inside the `then`
    });
}

foo().then(function(response){
    // Access the value inside the `then`
})

function* foo(){ // Notice the star. This is ES6, so new browsers, Nodes.js, and io.js only
    yield 1;
    yield 2;
    while(true) yield 3;
}

var foo = coroutine(function*(){
    var data = yield fetch("/echo/json"); // Notice the yield
    // The code here only executes _after_ the request is done
    return data.json(); // 'data' is defined
});

var main = coroutine(function*(){
   var bar = yield foo(); // Wait our earlier coroutine. It returns a promise
   // The server call is done here, and the code below executes when done
   var baz = yield fetch("/api/users/" + bar.userid); // Depends on foo's result
   console.log(baz); // Runs after both requests are done
});
main();

2016年(ES7)

在ES7中,这一点进一步标准化了,现在有几个建议,但在所有这些建议中,你可以等待承诺,这只是ES6提议的“糖”(尼克合成)通过添加同步并等待关键词。

async function foo(){
    var data = await fetch("/echo/json"); // Notice the await
    // code here only executes _after_ the request is done
    return data.json(); // 'data' is defined
}

另一个解决方案是通过序列执行器 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 将逐步评估所有运营商和表达式,如果某些缓慢功能的结果不准备好,则停止执行。

这里有更多的例子。

下面我写的例子表明如何

处理无同步的 HTTP 通话; 等待每个 API 通话的响应; 使用 Promise 模式; 使用 Promise.all 模式加入多个 HTTP 通话;

[
 "search?type=playlist&q=%22doom%20metal%22",
 "search?type=playlist&q=Adele"
]

对于每个项目,一个新的承诺将燃烧一个区块 - ExecutionBlock,打破结果,根据结果序列安排一个新的承诺集,这是 Spotify 用户对象的列表,并在 ExecutionProfileBlock 中无同步执行新的 HTTP 通话。

然后,你可以看到一个被遗弃的承诺结构,允许你扫描多个和完全无同步的遗弃的HTTP通话,并通过 Promise.all 加入每个子组的通话的结果。

-H "Authorization: Bearer {your access token}" 

我在这里讨论了这个解决方案。

等待

请求以无同步的方式工作,所以你不能像典型代码那样同步阅读数据。 但是,使用 async/await 你可以创建一个与常见的同步/序列风格相似的无同步代码. 处理响应数据的代码必须由一个无同步函数(在下面的剪辑中加载)并在它里面你需要在 foo()(whic)之前添加等待关键字。

async 函数 foo() { var url = 'https://jsonplaceholder.typicode.com/todos/1'; var result = (await fetch(url)).text(); // 或.json() return result; } async 函数 load() { var result = await foo(); console.log(result); } load();

记住,一个无与伦比的功能总是(显而易见)将其结果转化为一个承诺(因此它返回一个承诺)。