我想使用Promise完成以下任务:仅在某种状态准备就绪时才进一步执行。即例如轮询外部状态更改。

我已经尝试过使用Promise和async-await,但是没有得到想要的结果。我在这里做错什么,如何解决?

MDN docs有类似的东西,但是它们的settimeout在promise之内被调用了-尽管这并不是我想要的。

我希望console.log显示“现在可以使用此功能!” 5秒后,但是调用await promiseForState()之后,执行似乎停止了。



var state = false;

function stateReady (){
 state = true;
}


function promiseForState(){
	var msg = "good to go!";
	var promise = new Promise(function (resolve,reject){
        if (state){
            resolve(msg);
        }
    });

  return promise;
}

async function waiting (intro){

    var result = await promiseForState();
    console.log(intro + result)

}
setTimeout(stateReady,5000);
waiting("This function is now ");

最佳答案

根据您正在等待来自服务器的消息的评论,您似乎正在尝试解决X/Y problem。因此,我将回答“如何等待服务器消息”的问题,而不是等待全局变量更改。

如果您的网络API接受回调

诸如XMLHttpRequest和节点的Http.request()之类的大量联网API都是基于回调的。如果您使用的API是基于回调或事件的,则可以执行以下操作:

function myFunctionToFetchFromServer () {
    // example is jQuery's ajax but it can easily be replaced with other API
    return new Promise(function (resolve, reject) {
        $.ajax('http://some.server/somewhere', {
            success: resolve,
            error: reject
        });
    });
}

async function waiting (intro){
    var result = await myFunctionToFetchFromServer();
    console.log(intro + result);
}


如果您的网络API是基于承诺的

另一方面,如果您使用的是基于更新的基于诺言的联网API(例如fetch()),则只需等待诺言:

function myFunctionToFetchFromServer () {
    return fetch('http://some.server/somewhere');
}

async function waiting (intro){
    var result = await myFunctionToFetchFromServer();
    console.log(intro + result);
}


将网络访问与事件处理程序分离

请注意,以下内容仅是我的观点,也是javascript社区中的常规标准做法:

在上述两种情况下,一旦您做出承诺,就可以将网络API与waiting()事件处理程序分离。您只需要将承诺保存在其他地方。 Evert的答案显示了执行此操作的一种方法。

但是,以我不太谦逊的观点,您不应该这样做。在规模较大的项目中,这将导致难以追踪状态变化发生的来源。这就是我们在90年代和2000年代初使用javascript所做的工作。我们的代码中有很多events,例如onChangeonReadyonData,而不是作为函数参数传递的回调。结果是有时需要花费很长时间才能弄清楚什么代码触发了什么事件。

回调参数和promise强制事件生成器与事件使用者位于代码中的同一位置:

let this_variable_consumes_result_of_a_promise = await generate_a_promise();

this_function_generate_async_event((consume_async_result) => { /* ... */ });


从问题的措辞来看,您似乎想这样做。

..在代码中的某处:

this_function_generate_async_event(() => { set_global_state() });


..代码中的其他地方:

let this_variable_consumes_result_of_a_promise = await global_state();


我认为这是一种反模式。

在类构造函数中调用异步函数

这不仅是反模式,而且是不可能的(毫无疑问,当您发现无法返回异步结果时就发现了)。

但是,有些设计模式可以解决此问题。以下是公开异步创建的数据库连接的示例:

class MyClass {
    constructor () {
        // constructor logic
    }

    db () {
        if (this.connection) {
            return Promise.resolve(this.connection);
        }
        else {
            return new Promise (function (resolve, reject) {
                createDbConnection(function (error, conn) {
                    if (error) {
                        reject(error);
                    }
                    else {
                        this.connection = conn; // cache the connection
                        resolve(this.connection);
                    }
                });
            });
        }
    }
}


用法:

const myObj = new MyClass();

async function waiting (intro){
    const db = await myObj.db();
    db.doSomething(); // you can now use the database connection.
}


您可以从我对另一个问题的回答中了解有关异步构造函数的更多信息:Async/Await Class Constructor

09-20 18:54