梦情居士

文章 评论 浏览 30

梦情居士 2025-02-21 01:45:38

→有关使用不同示例的异步行为的更一般说明,请参见 为什么我的变量是在我的变量之后不变的,为什么我将其修改在功能中吗? - 异步代码参考

→如果您已经理解了问题,请跳到以下可能的解决方案。

a in

这是一个类比,希望能使同步和异步流更清晰地之间有所不同:

同步

想象您打电话给朋友,并要求他为您寻找东西。尽管可能需要一段时间,但您在电话上等待太空,直到您的朋友给您所需的答案。

当您进行包含“正常”代码的函数调用时,也会发生同样的情况:

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

var item = findItem();

// Do something with item
doSomethingElse();

即使 FindItem 可能需要很长时间才能执行, var item = var item = findItem(); 必须等待,直到函数返回结果。

异步

出于同样的原因, 您再次致电您的朋友。但是这次您告诉他您很着急,他应该在手机上给您回电。您挂断电话,离开房子,做您计划做的任何事情。一旦您的朋友给您回电,您就会处理他给您的信息。

这就是您执行AJAX请求时发生的事情。

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

执行并没有等待响应,而是立即继续执行,并且执行AJAX调用后的语句。为了最终获得响应,您提供了一个函数,一旦收到响应,a challback (请注意某件事?回电?)。在调用回调之前执行该呼叫后的任何语句。


解决方案

包含JavaScript!的异步性质,而某些异步操作提供同步的对应物(“ Ajax”也是如此),通常不愿意使用它们,尤其是在浏览器上下文中。

你为什么问不好?

JavaScript在浏览器的UI线程中运行,任何长期运行的过程都会锁定UI,从而使其无反应。此外,JavaScript的执行时间有一个上限,浏览器将询问用户是否继续执行。

所有这些都导致了非常糟糕的用户体验。用户将无法分辨出一切工作正常。此外,对于连接缓慢的用户而言,效果会更糟。

在以下内容中,我们将查看三种彼此之间建立的不同解决方案:

  • 承诺 ynnc/等待 (ES2017++,如果您使用的话,可在较旧的浏览器中使用transpiler或recenener)
  • 回调(在节点中流行)
  • then() (ES2015+)承诺(ES2015+)浏览器如果使用众多承诺库之一)

所有三个都在当前浏览器中可用,节点7+。


es2017+:promise async/等待

2017年在2017年发布的ecmascript版本引入了 andtax-level support syynChronionus函数。借助 async 等待,您可以以“同步样式”编写异步。该代码仍然具有异步,但是阅读/理解更容易。

异步/等待在承诺之上构建: async 函数始终返回承诺。 等待“取消包裹”的承诺,并且如果拒绝承诺,则可以解决承诺的价值或丢弃错误。

重要:您只能在 async 函数或 en-us/doc/web/javaScript/guide/模块“ rel =“ noreferrer”> javascript模块。顶级等待在模块之外不支持,因此您可能必须制作一个异步(立即调用函数表达式)启动 async 上下文如果不使用模块。

您可以阅读有关 noreferrer“> async 等待MDN上。

这是详细列出 delay 函数 finditem()上面的示例:

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

当前浏览器 node 版本支持 async/aync/negait 。您还可以在 recenererator 的帮助下,通过将代码转换为ES5来支持旧环境。 ,例如 babel )。


让函数接受回调

一个回调是当函数1传递给函数2时。函数2可以在准备就绪时调用函数1。在异步过程的上下文中,每当完成异步过程时,都会调用回调。通常,结果将传递给回调。

在问题的示例中,您可以进行 foo 接受回调,并将其用作 Success 回调。因此,这

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

foo 本身定义如下:

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

callback 将参考我们传递给<<<的函数。代码> foo 我们调用它,然后将其传递给 Success 。即,一旦AJAX请求成功, $。ajax 将调用回调,然后将响应传递给回调(可以使用 result> Result 来参考。 ,因为这就是我们定义回调的方式)。

您还可以在将响应传递给回调之前处理:

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

使用回调编写代码比看起来更容易。毕竟,浏览器中的JavaScript是事件驱动的(DOM事件)。接收Ajax响应只是事件。
当您必须使用第三方代码时,可能会出现困难,但是只要考虑应用程序流程,就可以解决大多数问题。


ES2015+: the

一个href =“ https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_object/global_objects/promise” rel =“ noreferrer”> Promise api ),但是它有很好的浏览器支持。也有许多库可以实现标准承诺API并提供其他方法来减轻异步功能的使用和组成(例如,)。

承诺是未来值的容器。当承诺收到值(已解决的)或取消(拒绝)时,它会通知所有想访问此值的“听众”。

比普通回调的优势在于,它们允许您将代码解除,并且更容易撰写。

这是使用承诺的示例:

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

delay()
  .then(function(v) { // `delay` returns a promise
    console.log(v); // Log the value once it is resolved
  })
  .catch(function(v) {
    // Or do something else if it is rejected
    // (it would not happen in this example, since `reject` is not called).
  });
.as-console-wrapper { max-height: 100% !important; top: 0; }

应用于我们的Ajax电话,我们可以使用这样的承诺:

function ajax(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      resolve(this.responseText);
    };
    xhr.onerror = reject;
    xhr.open('GET', url);
    xhr.send();
  });
}

ajax("https://jsonplaceholder.typicode.com/todos/1")
  .then(function(result) {
    console.log(result); // Code depending on result
  })
  .catch(function() {
    // An error occurred
  });
.as-console-wrapper { max-height: 100% !important; top: 0; }

描述承诺提供的所有优势超出了此答案的范围,但是如果您编写新代码,则应认真考虑它们。它们提供了很好的抽象和您的代码分离。

有关承诺的更多信息: html5 rocks -javascript Promises promises

旁注:jQuery的延期对象

延迟对象标准化)。他们的行为几乎像承诺,但暴露了略有不同的API。

jQuery的每种AJAX方法已经返回一个“递延对象”(实际上是递延对象的承诺),您可以从函数中返回:

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

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

侧面注意:promise gotchas new Chep

牢记承诺和递延对象只是容器 /em>对于未来的价值,它们不是价值本身。例如,假设您有以下内容:

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
}

此代码误解了上述异步问题。具体来说, $。ajax()在检查服务器上的“/密码”页面时不会冻结代码 - 它将请求发送到服务器,并且在等待时,它立即返回jQuery AJAX递延对象,而不是服务器的响应。这意味着如果语句将始终获取此延期对象,请将其视为 true ,然后继续以用户登录。不好。

但是修复程序很容易:

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”调用

,一些(!)异步操作具有同步的对应物。我不主张他们的使用,但为了完整的缘故,这是您执行同步呼叫的方式:

如果

直接使用 xmlhttprequest 对象,将 false 作为第三个参数作为 .open

jQuery

如果您使用 jquery ,您可以设置 async 选项 false 。请注意,由于jQuery 1.8,此选项是弃用
然后,您可以仍然使用成功回调,或访问 ResponseText jqxhr对象

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

如果您使用任何其他jquery ajax方法,例如 $。get $。getjson 等。 。

抬头!无法同步 jsonp 请求。 JSONP本质上总是异步的(甚至不考虑此选项的另一个原因)。

→ For a more general explanation of asynchronous behaviour with different examples, see Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

→ If you already understand the problem, skip to the possible solutions below.

The problem

The A in Ajax stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example, $.ajax returns immediately and the next statement, return result;, is executed before the function you passed as success callback was even called.

Here is an analogy which hopefully makes the difference between synchronous and asynchronous flow clearer:

Synchronous

Imagine you make a phone call to a friend and ask him to look something up for you. Although it might take a while, you wait on the phone and stare into space, until your friend gives you the answer that you needed.

The same is happening when you make a function call containing "normal" code:

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

var item = findItem();

// Do something with item
doSomethingElse();

Even though findItem might take a long time to execute, any code coming after var item = findItem(); has to wait until the function returns the result.

Asynchronous

You call your friend again for the same reason. But this time you tell him that you are in a hurry and he should call you back on your mobile phone. You hang up, leave the house, and do whatever you planned to do. Once your friend calls you back, you are dealing with the information he gave to you.

That's exactly what's happening when you do an Ajax request.

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

Instead of waiting for the response, the execution continues immediately and the statement after the Ajax call is executed. To get the response eventually, you provide a function to be called once the response was received, a callback (notice something? call back ?). Any statement coming after that call is executed before the callback is called.


Solution(s)

Embrace the asynchronous nature of JavaScript! While certain asynchronous operations provide synchronous counterparts (so does "Ajax"), it's generally discouraged to use them, especially in a browser context.

Why is it bad do you ask?

JavaScript runs in the UI thread of the browser and any long-running process will lock the UI, making it unresponsive. Additionally, there is an upper limit on the execution time for JavaScript and the browser will ask the user whether to continue the execution or not.

All of this results in a really bad user experience. The user won't be able to tell whether everything is working fine or not. Furthermore, the effect will be worse for users with a slow connection.

In the following we will look at three different solutions that are all building on top of each other:

  • Promises with async/await (ES2017+, available in older browsers if you use a transpiler or regenerator)
  • Callbacks (popular in node)
  • Promises with then() (ES2015+, available in older browsers if you use one of the many promise libraries)

All three are available in current browsers, and node 7+.


ES2017+: Promises with async/await

The ECMAScript version released in 2017 introduced syntax-level support for asynchronous functions. With the help of async and await, you can write asynchronous in a "synchronous style". The code is still asynchronous, but it's easier to read/understand.

async/await builds on top of promises: an async function always returns a promise. await "unwraps" a promise and either result in the value the promise was resolved with or throws an error if the promise was rejected.

Important: You can only use await inside an async function or in a JavaScript module. Top-level await is not supported outside of modules, so you might have to make an async IIFE (Immediately Invoked Function Expression) to start an async context if not using a module.

You can read more about async and await on MDN.

Here is an example that elaborates the delay function findItem() above:

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

Current browser and node versions support async/await. You can also support older environments by transforming your code to ES5 with the help of regenerator (or tools that use regenerator, such as Babel).


Let functions accept callbacks

A callback is when function 1 is passed to function 2. Function 2 can call function 1 whenever it is ready. In the context of an asynchronous process, the callback will be called whenever the asynchronous process is done. Usually, the result is passed to the callback.

In the example of the question, you can make foo accept a callback and use it as success callback. So this

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

becomes

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

Here we defined the function "inline" but you can pass any function reference:

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

foo(myCallback);

foo itself is defined as follows:

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

callback will refer to the function we pass to foo when we call it and we pass it on to success. I.e. once the Ajax request is successful, $.ajax will call callback and pass the response to the callback (which can be referred to with result, since this is how we defined the callback).

You can also process the response before passing it to the callback:

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

It's easier to write code using callbacks than it may seem. After all, JavaScript in the browser is heavily event-driven (DOM events). Receiving the Ajax response is nothing else but an event.
Difficulties could arise when you have to work with third-party code, but most problems can be solved by just thinking through the application flow.


ES2015+: Promises with then()

The Promise API is a new feature of ECMAScript 6 (ES2015), but it has good browser support already. There are also many libraries which implement the standard Promises API and provide additional methods to ease the use and composition of asynchronous functions (e.g., bluebird).

Promises are containers for future values. When the promise receives the value (it is resolved) or when it is canceled (rejected), it notifies all of its "listeners" who want to access this value.

The advantage over plain callbacks is that they allow you to decouple your code and they are easier to compose.

Here is an example of using 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);
  });
}

delay()
  .then(function(v) { // `delay` returns a promise
    console.log(v); // Log the value once it is resolved
  })
  .catch(function(v) {
    // Or do something else if it is rejected
    // (it would not happen in this example, since `reject` is not called).
  });
.as-console-wrapper { max-height: 100% !important; top: 0; }

Applied to our Ajax call we could use promises like this:

function ajax(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      resolve(this.responseText);
    };
    xhr.onerror = reject;
    xhr.open('GET', url);
    xhr.send();
  });
}

ajax("https://jsonplaceholder.typicode.com/todos/1")
  .then(function(result) {
    console.log(result); // Code depending on result
  })
  .catch(function() {
    // An error occurred
  });
.as-console-wrapper { max-height: 100% !important; top: 0; }

Describing all the advantages that promise offer is beyond the scope of this answer, but if you write new code, you should seriously consider them. They provide a great abstraction and separation of your code.

More information about promises: HTML5 rocks - JavaScript Promises.

Side note: jQuery's deferred objects

Deferred objects are jQuery's custom implementation of promises (before the Promise API was standardized). They behave almost like promises but expose a slightly different API.

Every Ajax method of jQuery already returns a "deferred object" (actually a promise of a deferred object) which you can just return from your function:

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

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

Side note: Promise gotchas

Keep in mind that promises and deferred objects are just containers for a future value, they are not the value itself. For example, suppose you had the following:

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
}

This code misunderstands the above asynchronous issues. Specifically, $.ajax() doesn't freeze the code while it checks the '/password' page on your server - it sends a request to the server and while it waits, it immediately returns a jQuery Ajax Deferred object, not the response from the server. That means the if statement is going to always get this Deferred object, treat it as true, and proceed as though the user is logged in. Not good.

But the fix is easy:

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

Not recommended: Synchronous "Ajax" calls

As I mentioned, some(!) asynchronous operations have synchronous counterparts. I don't advocate their use, but for completeness' sake, here is how you would perform a synchronous call:

Without jQuery

If you directly use a XMLHttpRequest object, pass false as third argument to .open.

jQuery

If you use jQuery, you can set the async option to false. Note that this option is deprecated since jQuery 1.8.
You can then either still use a success callback or access the responseText property of the jqXHR object:

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

If you use any other jQuery Ajax method, such as $.get, $.getJSON, etc., you have to change it to $.ajax (since you can only pass configuration parameters to $.ajax).

Heads up! It is not possible to make a synchronous JSONP request. JSONP by its very nature is always asynchronous (one more reason to not even consider this option).

如何从异步电话中返回响应?

梦情居士 2025-02-20 08:00:22

您不能混合 async void backgroundworker.dowork ,因为一旦您击中第一个等待 dowork 处理程序已向工人出现。

我建议您完全删除 backgroundworker ,只需使用等待即可。

示例代码似乎缺少信息:什么是 pings count 文件?我试图猜测它是如何工作的,但是看来您正在为这些使用某种缓存字段,至少在 file 的情况下)可能是不可接受的。

SemaphoreSlim _sem = new SemaphoreSlim(1, 1);

private void Ping_Btn_Click(object sender, EventArgs e)
{
    if (!await _sem.WaitAsync(0))  // bail-out if already executing
        return;
    try
    {
        int counter = 1;
        // For every ping object    
        foreach (Ping pinger in pings)
        {
            // Set the appropriate UI element properties
            // Create initial control object
            // Finds controls in which their name matches the string
            (this.Controls.Find("greenBox" + counter, true).FirstOrDefault() as Control)?.Visible = false;
            (this.Controls.Find("orangeBox" + counter, true).FirstOrDefault() as Control)?.Visible = false;
            (this.Controls.Find("redBox" + counter, true).FirstOrDefault() as Control)?.Visible = true;
            (this.Controls.Find("status_Lbl" + counter, true).FirstOrDefault() as Control)?.Text = "Initiated...";
            counter++;
        }
        // Take input from text box
        count = Convert.ToInt32(pingSeconds_TxtBox.Text);
        // Start operation
        await DoPing();
    }
    finally
    {
        // release lock
        _sem.Release();
    }
}

private async Task DoPing()
{
    try
    {
        // Write to log file
        await file.WriteAsync("Starting job...\n");
        await file.WriteAsync("Requested amount of pings: " + count + "\n");
        // Create date object for logs
        DateTime localDate = DateTime.Now;

        using (System.Net.NetworkInformation.Ping pinger = new System.Net.NetworkInformation.Ping())
        {
            for (int i = 0; i < count; i++)
            {
                foreach (Ping pingObj in pings)
                {
                    try
                    {
                        var pingReply = await pinger.SendAsync(pingObj.IpAddress);
                        // Write log file
                        await file.WriteLineAsync(localDate.TimeOfDay + " | Friendly Name " + pingObj.FriendlyName + " | Ping: " + pingReply.Address + " | Status " + pingReply.Status + " | Time: " + pingReply.RoundtripTime);
                        if (pingReply.Status == IPStatus.Success)
                        {
                            pingObj.SuccessfulPings += 1;
                        }
                        else // Unsuccessful ping has been sent
                        {
                            pingObj.FailedPings += 1;
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.ToString());
                    }
                }
                await Task.Delay(1000);
            }
        }
    }
    catch (Exception a)
    {
        Debug.WriteLine(a.ToString());
    }
}

You can't mix async void and BackgroundWorker.DoWork, because as soon as you hit the first await then the DoWork handler appears to the worker that it has finished.

I would advise you to remove the BackgroundWorker entirely, and just use await.

There appears to be missing information from your sample code: what are pings count and file? I have tried to guess how that works, but it looks like you are using some kind of cached field for these, which (at least in the case of file) is probably inadvisable.

SemaphoreSlim _sem = new SemaphoreSlim(1, 1);

private void Ping_Btn_Click(object sender, EventArgs e)
{
    if (!await _sem.WaitAsync(0))  // bail-out if already executing
        return;
    try
    {
        int counter = 1;
        // For every ping object    
        foreach (Ping pinger in pings)
        {
            // Set the appropriate UI element properties
            // Create initial control object
            // Finds controls in which their name matches the string
            (this.Controls.Find("greenBox" + counter, true).FirstOrDefault() as Control)?.Visible = false;
            (this.Controls.Find("orangeBox" + counter, true).FirstOrDefault() as Control)?.Visible = false;
            (this.Controls.Find("redBox" + counter, true).FirstOrDefault() as Control)?.Visible = true;
            (this.Controls.Find("status_Lbl" + counter, true).FirstOrDefault() as Control)?.Text = "Initiated...";
            counter++;
        }
        // Take input from text box
        count = Convert.ToInt32(pingSeconds_TxtBox.Text);
        // Start operation
        await DoPing();
    }
    finally
    {
        // release lock
        _sem.Release();
    }
}

private async Task DoPing()
{
    try
    {
        // Write to log file
        await file.WriteAsync("Starting job...\n");
        await file.WriteAsync("Requested amount of pings: " + count + "\n");
        // Create date object for logs
        DateTime localDate = DateTime.Now;

        using (System.Net.NetworkInformation.Ping pinger = new System.Net.NetworkInformation.Ping())
        {
            for (int i = 0; i < count; i++)
            {
                foreach (Ping pingObj in pings)
                {
                    try
                    {
                        var pingReply = await pinger.SendAsync(pingObj.IpAddress);
                        // Write log file
                        await file.WriteLineAsync(localDate.TimeOfDay + " | Friendly Name " + pingObj.FriendlyName + " | Ping: " + pingReply.Address + " | Status " + pingReply.Status + " | Time: " + pingReply.RoundtripTime);
                        if (pingReply.Status == IPStatus.Success)
                        {
                            pingObj.SuccessfulPings += 1;
                        }
                        else // Unsuccessful ping has been sent
                        {
                            pingObj.FailedPings += 1;
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.ToString());
                    }
                }
                await Task.Delay(1000);
            }
        }
    }
    catch (Exception a)
    {
        Debug.WriteLine(a.ToString());
    }
}

循环完成前退出Dowork的背景工人

梦情居士 2025-02-19 22:24:43

soup.find 找不到任何东西时,它将返回。在中拨打 s.find_all 如果S:或 not none:

因此,您的代码变为:

r = requests.get('https://www.marketsandmarkets.com/Market-Reports/rocket-missile-market-203298804.html/')
soup = BeautifulSoup(r.content, 'html.parser')
s = soup.find('div', class_='entry-content') 
if s is not None:
    content = s.find_all('p')
    print(content) 
else:
    print("Didn't find what I was looking for...")

或也许:

content = s.find_all('p') if s is not None else []
print(content)

https://crummy.com/software /BeautifulSoup/bs4/doc/#查找

When soup.find does not find anything, it returns None. Guard your s.find_all call with if s: or if s in not None:.

So your code becomes:

r = requests.get('https://www.marketsandmarkets.com/Market-Reports/rocket-missile-market-203298804.html/')
soup = BeautifulSoup(r.content, 'html.parser')
s = soup.find('div', class_='entry-content') 
if s is not None:
    content = s.find_all('p')
    print(content) 
else:
    print("Didn't find what I was looking for...")

or maybe:

content = s.find_all('p') if s is not None else []
print(content)

Ref: https://crummy.com/software/BeautifulSoup/bs4/doc/#find

美丽的汤错误:&#x27; nontype&#x27;对象没有属性&#x27; find_all&#x27;

梦情居士 2025-02-19 17:19:02
awk '
  NR==1{
    printf "%-16s | %-9s | %s\n", "Date","Weekday","Shift"; next   
  }
  {
    "date -d \"" $0 "\" \"+%d-%m-%Y %H:%M | %A\"" | getline d
    gsub(/:/, "", $2); t=int($2)
    printf "%-28s | %s\n", d ,(t > 73000 && t < 193000) ? "Morning" : "Night"
  }' file.csv

Date             | Weekday   | Shift
09-06-2022 22:30 | Thursday  | Night
10-06-2022 15:55 | Friday    | Morning
11-06-2022 00:34 | Saturday  | Night
11-06-2022 19:51 | Saturday  | Night
13-06-2022 11:34 | Monday    | Morning
15-06-2022 03:59 | Wednesday | Night
18-06-2022 16:13 | Saturday  | Morning
19-06-2022 00:24 | Sunday    | Night
19-06-2022 00:25 | Sunday    | Night
19-06-2022 00:25 | Sunday    | Night
19-06-2022 00:25 | Sunday    | Night
awk '
  NR==1{
    printf "%-16s | %-9s | %s\n", "Date","Weekday","Shift"; next   
  }
  {
    "date -d \"" $0 "\" \"+%d-%m-%Y %H:%M | %A\"" | getline d
    gsub(/:/, "", $2); t=int($2)
    printf "%-28s | %s\n", d ,(t > 73000 && t < 193000) ? "Morning" : "Night"
  }' file.csv

Date             | Weekday   | Shift
09-06-2022 22:30 | Thursday  | Night
10-06-2022 15:55 | Friday    | Morning
11-06-2022 00:34 | Saturday  | Night
11-06-2022 19:51 | Saturday  | Night
13-06-2022 11:34 | Monday    | Morning
15-06-2022 03:59 | Wednesday | Night
18-06-2022 16:13 | Saturday  | Morning
19-06-2022 00:24 | Sunday    | Night
19-06-2022 00:25 | Sunday    | Night
19-06-2022 00:25 | Sunday    | Night
19-06-2022 00:25 | Sunday    | Night

提取日期并秘密到工作日

梦情居士 2025-02-19 12:12:21

这是你想要的吗?

data(iris)
library(ggplot2)

ggplot(data=iris, aes(x = Sepal.Length, y = Sepal.Width)) + 
  geom_point(aes(color=Species, shape=Species)) +
  xlab("Sepal Length") +  ylab("Sepal Width") +
  ggtitle("Sepal Length-Width") +
  facet_wrap(~Species)+ 
  geom_label(data = data.frame(x = 6, y = 5, Species = "setosa", 
                              label = "this is interesting\nwhat now"), 
                                  aes(x = x, y = y, label = label), size = 4)

Is this what you want?

data(iris)
library(ggplot2)

ggplot(data=iris, aes(x = Sepal.Length, y = Sepal.Width)) + 
  geom_point(aes(color=Species, shape=Species)) +
  xlab("Sepal Length") +  ylab("Sepal Width") +
  ggtitle("Sepal Length-Width") +
  facet_wrap(~Species)+ 
  geom_label(data = data.frame(x = 6, y = 5, Species = "setosa", 
                              label = "this is interesting\nwhat now"), 
                                  aes(x = x, y = y, label = label), size = 4)

enter image description here

如何在tag_facets()中创建新行?

梦情居士 2025-02-19 08:47:03

您是否有要订阅可观察到的特定原因?

如果您只需要阅读组件初始化的查询参数,请尝试以下操作:
this.route.snapshot.queryparammap.get('param')

Is there a particular reason you want to subscribe to the observable?

If all you need is to read the query parameters on component initialization, then try this instead:
this.route.snapshot.queryParamMap.get('param')

无法检索Queryparams Angular 14

梦情居士 2025-02-18 22:28:03

该问题(与结果构建者有关)是在Swift 5.8中固定的。根据

这是5.7中的一个错误,以前汇编并影响了编译时间性能。我已经在论坛帖子中概述了这个问题 - https://forums.swift.org/t/impreved-result-builder-implementation-in-swift-5-8/63192 “结构诊断”子段。

The issue (which had to do with result builders) is fixed in Swift 5.8. According to an Apple engineer on GitHub:

This was a bug in 5.7 that previously compiled and impacted compile time performance. I have outlined this issue in the forums post - https://forums.swift.org/t/improved-result-builder-implementation-in-swift-5-8/63192 "Structural Diagnostics" sub-section.

Swift 5.7-`如果让```''

梦情居士 2025-02-18 22:04:11

有很多方法:

HTML代码:

<a id="b1" class="btnClick" type="button">B1M</a>
<a id="b2" class="btnClick" type="button">B2M</a>

一个是:
您可以在Selector jQuery中添加多个ID。

var b1 = $("#b1"), b2 = $("#b2");

b1.add(b2).click(function(){
   alert('clicked', this.id)
})

这是链接: fiddle

另一个是:
您可以将同一类给所有标签

jQuery代码:

$(".btnClick").click(function(){
   alert('clicked', this.id)
})

这是另一个链接: fiddle

There were many ways:

HTML Code:

<a id="b1" class="btnClick" type="button">B1M</a>
<a id="b2" class="btnClick" type="button">B2M</a>

One is:
You can add multiple ids in selector jQuery.

var b1 = $("#b1"), b2 = $("#b2");

b1.add(b2).click(function(){
   alert('clicked', this.id)
})

Here is the link: Fiddle

another one is :
You can give same class to all tags

jQuery code:

$(".btnClick").click(function(){
   alert('clicked', this.id)
})

Here is Another Link : Fiddle

致电funtion on Button单击事件,而不是通过ID

梦情居士 2025-02-18 22:01:47

您不应具有通过 QuizQuestions 数组进行迭代的循环。此功能应仅处理 QuizQuestions [CurrentQuestion] 。当用户转到下一个问题而不是此功能时,应递增 CurrentQuestion 索引。

var questionOne = function() {
  // create container to hold questions and answer options & give it a class name
  var questionsDiv = document.createElement("div");
  questionsDiv.className = "questions-div";

  // create question stem, give it a class name, add its content, & append to questionsDiv
  var questionStem = document.createElement("h2");
  questionStem.className = "question-stem";
  questionStem.innerText = quizQuestions[currentQuestion].question;
  questionsDiv.append(questionStem);

  // create container to hold answer option buttons
  var answerOptionsDiv = document.createElement("div");

  // create footer container, give it a class name, & append to the questionsContainer
  var footerDiv = document.createElement("div");
  footerDiv.className = "footer-div";
  questionsContainer.append(footerDiv);

  // create footer text (correct/wrong), give it a class name, & append to footerDiv
  var footerTextCorrect = document.createElement("h2");
  footerTextCorrect.className = "footer-text-correct";
  footerTextCorrect.innerText = "Correct!";
  footerDiv.append(footerTextCorrect);

  var footerTextWrong = document.createElement("h2");
  footerTextWrong.className = "footer-text-wrong";
  footerTextWrong.innerText = "Wrong!";
  footerDiv.append(footerTextWrong);

  // append questionsDiv to main questions container
  questionsContainer.append(questionsDiv);

  // append answerOptionsDiv to questions container
  questionsDiv.append(answerOptionsDiv);
  console.log(quizQuestions[currentQuestion].question);

  for (let j = 1; j <= 4; j++) {
    console.log(`${j}. ${quizQuestions[currentQuestion].options[`${j}`]}`);

    // create buttons for answer options and add their content
    var optionBtnOne = document.createElement("button");
    optionBtnOne.innerText = `${j}. ${
        quizQuestions[currentQuestion].options[`${j}`]
      }`;
    // append button to answerOptionsDiv
    answerOptionsDiv.append(optionBtnOne);
    optionBtnOne.addEventListener("click", selectAnswer);
    optionBtnOne.setAttribute(
      "id",
      `${quizQuestions[currentQuestion].options[`${j}`]}`
    );
  }
};

You shouldn't have the loop that iterates through the quizQuestions array. This function should just process quizQuestions[currentQuestion]. The currentQuestion index should be incremented when the user goes to the next question, not in this function.

var questionOne = function() {
  // create container to hold questions and answer options & give it a class name
  var questionsDiv = document.createElement("div");
  questionsDiv.className = "questions-div";

  // create question stem, give it a class name, add its content, & append to questionsDiv
  var questionStem = document.createElement("h2");
  questionStem.className = "question-stem";
  questionStem.innerText = quizQuestions[currentQuestion].question;
  questionsDiv.append(questionStem);

  // create container to hold answer option buttons
  var answerOptionsDiv = document.createElement("div");

  // create footer container, give it a class name, & append to the questionsContainer
  var footerDiv = document.createElement("div");
  footerDiv.className = "footer-div";
  questionsContainer.append(footerDiv);

  // create footer text (correct/wrong), give it a class name, & append to footerDiv
  var footerTextCorrect = document.createElement("h2");
  footerTextCorrect.className = "footer-text-correct";
  footerTextCorrect.innerText = "Correct!";
  footerDiv.append(footerTextCorrect);

  var footerTextWrong = document.createElement("h2");
  footerTextWrong.className = "footer-text-wrong";
  footerTextWrong.innerText = "Wrong!";
  footerDiv.append(footerTextWrong);

  // append questionsDiv to main questions container
  questionsContainer.append(questionsDiv);

  // append answerOptionsDiv to questions container
  questionsDiv.append(answerOptionsDiv);
  console.log(quizQuestions[currentQuestion].question);

  for (let j = 1; j <= 4; j++) {
    console.log(`${j}. ${quizQuestions[currentQuestion].options[`${j}`]}`);

    // create buttons for answer options and add their content
    var optionBtnOne = document.createElement("button");
    optionBtnOne.innerText = `${j}. ${
        quizQuestions[currentQuestion].options[`${j}`]
      }`;
    // append button to answerOptionsDiv
    answerOptionsDiv.append(optionBtnOne);
    optionBtnOne.addEventListener("click", selectAnswer);
    optionBtnOne.setAttribute(
      "id",
      `${quizQuestions[currentQuestion].options[`${j}`]}`
    );
  }
};

为什么在这个问题中出现所有问题的答案选项?

梦情居士 2025-02-17 19:39:01

运行 Expo Start ,您应该很好!遇到了同一问题,这解决了它。

Run expo start and you should be good to go! Ran into the same issue and this solved it.

CommandError:从Expo服务器获取版本信息时出乎意料的响应:未定义。反应天然博览会

梦情居士 2025-02-17 12:43:44

接受的答案不是一个很好的一般解决方案,它不会限制小数点的数量,它只是切断了可能是在小数后可能或不可能的字符。

正确的答案是使用 tofixed ,例如Mel Carlo Iguis的答案。您可以在设置状态之前每次调用 tofixed

setNum(Number(newValue.toFixed(1))) // 1 for 1 decimal place, adjust as needed

尽管该方法丢失了信息 - 如果要保留 num 高精度以进行将来的计算,则可以使用在实际渲染步骤中tofixed 这是我建议的模式

<div> {num.toFixed(1)} </div>

The accepted answer isn't a good general solution, it doesn't limit the number of decimal points, it just cuts off characters that may or may not be after the decimal.

The correct answer is using toFixed, like Mel Carlo Iguis's answer. You could call toFixed everytime before setting state:

setNum(Number(newValue.toFixed(1))) // 1 for 1 decimal place, adjust as needed

Although that method loses information-- if you want to keep num high-precision for future calculations, you can instead just use toFixed during the actual render step. This is the pattern I'd recommend:

<div> {num.toFixed(1)} </div>

如何在React中设置最大小数

梦情居士 2025-02-16 11:56:50

对于第一种情况,

这是.htacess的代码

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d

RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$ [NC]
RewriteRule ^ http://www.example1.com%{REQUEST_URI} [L,NE,P]

For the first scenario

this is code for .htacess

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d

RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$ [NC]
RewriteRule ^ http://www.example1.com%{REQUEST_URI} [L,NE,P]

配置php .htaccess文件

梦情居士 2025-02-15 21:04:45

请尝试以下解决方案。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, ProductCategory VARCHAR(30), _year CHAR(4));
INSERT INTO @tbl (ProductCategory, _year) VALUES
('Toys', '2008'),
('Footwear', '2008'),
('Cookware', '2008'),
('Toys', '2009'),
('Toys', '2007'),
('Footwear', '2009'),
('Footwear', '2007'),
('Clothes', '2008');
-- DDL and sample data population, end

;WITH rs AS
(
    SELECT * 
       , total_count = COUNT(*) OVER (PARTITION BY ProductCategory ORDER BY ProductCategory)
       , _2008_count = SUM(IIF (_year='2008', 1, 0)) OVER (PARTITION BY ProductCategory ORDER BY ProductCategory)
    FROM @tbl
)
SELECT ID, ProductCategory, _year 
FROM rs
WHERE total_count <> _2008_count
ORDER BY ID;

输出

+----+-----------------+-------+
| ID | ProductCategory | _year |
+----+-----------------+-------+
|  1 | Toys            |  2008 |
|  2 | Footwear        |  2008 |
|  4 | Toys            |  2009 |
|  5 | Toys            |  2007 |
|  6 | Footwear        |  2009 |
|  7 | Footwear        |  2007 |
+----+-----------------+-------+

Please try the following solution.

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, ProductCategory VARCHAR(30), _year CHAR(4));
INSERT INTO @tbl (ProductCategory, _year) VALUES
('Toys', '2008'),
('Footwear', '2008'),
('Cookware', '2008'),
('Toys', '2009'),
('Toys', '2007'),
('Footwear', '2009'),
('Footwear', '2007'),
('Clothes', '2008');
-- DDL and sample data population, end

;WITH rs AS
(
    SELECT * 
       , total_count = COUNT(*) OVER (PARTITION BY ProductCategory ORDER BY ProductCategory)
       , _2008_count = SUM(IIF (_year='2008', 1, 0)) OVER (PARTITION BY ProductCategory ORDER BY ProductCategory)
    FROM @tbl
)
SELECT ID, ProductCategory, _year 
FROM rs
WHERE total_count <> _2008_count
ORDER BY ID;

Output

+----+-----------------+-------+
| ID | ProductCategory | _year |
+----+-----------------+-------+
|  1 | Toys            |  2008 |
|  2 | Footwear        |  2008 |
|  4 | Toys            |  2009 |
|  5 | Toys            |  2007 |
|  6 | Footwear        |  2009 |
|  7 | Footwear        |  2007 |
+----+-----------------+-------+

SQL Server-如何根据两个或多列的数据组合过滤数据

梦情居士 2025-02-15 03:55:38

查看 evaliate 的左侧侧栏。底部附近是“编程语言”部分。它列出了Python 3.7至3.10版的可用性。

您将需要使用其中一个版本的Python创建一个新的环境。

Look at the left side-bar on PyPi package page for evaluate. Near the bottom is the "Programming Language" section. It lists availability for Python version 3.7 to 3.10.

You will need to create a new environment with one of those versions of Python.

找不到满足要求评估的版本

梦情居士 2025-02-14 19:13:47

UTF-8中有两种不同的强调字符表示,并分解了。

  • 组成的表示形式使用单个编码点,é \ u00e9 \ code> \ xc3 \ xa9
  • 分解表示形式使用两个codepoints,base glyph e e 的组合标记

\ u0065 \ x65 以及Accent \ u0301 \ xcc \ xcc \ x81

也就是说,在使用UTF-8的文件名接受文件名时,您应该在将这些名称写入磁盘和/或创建链接之前,以避免此问题,以避免此问题和其他问题。

要归一化为组成和分解的表格:

$input = "e\xCC\x81";
$norm_c = Normalizer::normalize($input, Normalizer::FORM_C);
$norm_d = Normalizer::normalize($input, Normalizer::FORM_D);

var_dump(
    $input, bin2hex($input),
    $norm_c, bin2hex($norm_c),
    $norm_d, bin2hex($norm_d)
);

输出:

string(3) "é"
string(6) "65cc81"
string(2) "é"
string(4) "c3a9"
string(3) "é"
string(6) "65cc81"

您还应检查OS和文件系统如何处理UTF-8文件名。有些人只会将任何系列字节写为文件名,有些会很挑剔和拒绝,而另一些字节将执行自己的标准化,而这些标准化可能并不符合您在应用程序中选择的内容。

There are two different representations of common accented characters in UTF-8, composed, and decomposed.

  • The composed representation uses a single codepoint, é \u00e9 \xC3\xA9
  • The decomposed representation uses two codepoints, the base glyph e \u0065 \x65 and the combining mark for the accent \u0301 \xCC\x81

What you have posted in your question uses the latter, decomposed form. You may, in the short term, get your request to work by supplying the comosed form of that character.

That said, when accepting filenames with UTF-8 you should make a point of normalizing those names before writing them to disk, and/or creating links, to avoid this and other problems.

To normalize to Composed and Decomposed forms:

$input = "e\xCC\x81";
$norm_c = Normalizer::normalize($input, Normalizer::FORM_C);
$norm_d = Normalizer::normalize($input, Normalizer::FORM_D);

var_dump(
    $input, bin2hex($input),
    $norm_c, bin2hex($norm_c),
    $norm_d, bin2hex($norm_d)
);

Output:

string(3) "é"
string(6) "65cc81"
string(2) "é"
string(4) "c3a9"
string(3) "é"
string(6) "65cc81"

You should also check how your OS and filesystem handle UTF-8 filenames. Some will simply write any series of bytes as the filename, some will be picky and reject, and others will perform their own normalization that may not neccessarily match what you have chosen in your app.

PHP-重音文件名上的读取文件

更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

更多

友情链接

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文