JavaScript 中的异步编程,无需混乱的回调

发布于 2024-08-21 05:41:10 字数 1108 浏览 4 评论 0原文

我想将异步函数转换为同步函数。

function fetch() {
  var result = 'snap!';
  $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function messyCallback(data){
    result = data;
  });
  return result;
}

document.write(fetch());​

查看实际操作

结果始终是“snap!”,因为 $.getJSON 运行fetch() 完成后。

我的第一个想法是:

function fetch() {
  var result = 'snap!';
  $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function messyCallback(data){
    result = data;
  });
  while (true) {
    if (result != 'snap!') return result;
  }
}

它不起作用并且还会关闭浏览器。

我读到了 JS 1.7 中的生成器和迭代器,但我不知道如何将其应用到我的问题上。

这个问题实际上与 jQuery 无关。 $.getJSON 可以是任何其他异步函数。

I want to turn an asynchronous function to the synchronous.

function fetch() {
  var result = 'snap!';
  $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function messyCallback(data){
    result = data;
  });
  return result;
}

document.write(fetch());​

See in action

The result always will be 'snap!', because $.getJSON run after fetch() is done.

My first idea was:

function fetch() {
  var result = 'snap!';
  $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function messyCallback(data){
    result = data;
  });
  while (true) {
    if (result != 'snap!') return result;
  }
}

It doesn't work and also blow off the browser.

I read about generators and iterators in JS 1.7, but I have no idea how to apply it to my problem.

This question is not really about jQuery. Instead of $.getJSON could be any another asynchronous function.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

罗罗贝儿 2024-08-28 05:41:10

另请参阅此问题:停止 JavaScript 执行而不锁定浏览器

完全按照自己的意愿去做是行不通的。在单线程事件驱动环境中,您无法从异步创建同步(只能反过来!)。您应该拥抱该语言的异步特性,并围绕处理回调开发自己的一致风格,以便您的代码可读/可维护。例如,您可以选择不在回调闭包内执行任何实际工作,而只是为了清楚起见而调用另一个顶级函数/方法。

See this question also: Halt JavaScript execution without locking up the browser

Doing exactly what you want doesn't work. You can't create synchronousness from asynchronousness (only the other way around!) in a single-threaded event-driven environment. You should embrace the async nature of the language, and develop your own consistent style around handling callbacks so that your code is readable/maintainable. You could, for instance, choose to never do any real work inside a callback closure, but simply call another top-level function/method for clarity.

累赘 2024-08-28 05:41:10

您想要推出自己的使用 $.ajax({async:false}) 的 $.getSyncJSON。请参阅:http://api.jquery.com/jQuery.ajax/

不过,我必须建议您不要采取这种做法。您可以轻松锁定浏览器以阻止所有输入,使您的 UI 受网络支配。但如果您知道自己在做什么并且确定自己的用例,那就去做吧。

You want to roll your own $.getSyncJSON that uses $.ajax({async:false}). See: http://api.jquery.com/jQuery.ajax/.

I must advise you against this course of action, however. You can easily lock up the browser from all input, putting your UI at the mercy of the network. But if you know what you are doing and are sure of your use case, go for it.

2024-08-28 05:41:10

不要编写像 fetch 这样返回值的辅助方法,而是让它们接受另一个函数(“接收器”),将结果传递给:

function fetch(receiver) {

    $.getJSON("blah...", function(data) {

        receiver(data);
    });
}

显然这是多余的,因为它正是 getJSON< 的方式。 /code> 已经可以工作,但在更实际的示例中,fetch 函数会在传递结果之前以某种方式处理或过滤结果。

然后,而不是:

document.write(fetch());​

你会这样做:

fetch(function(result) { document.write(result); });

生成器可用于使异步代码在风格上更加线性。每次您需要一些异步结果时,您都会生成一个函数来启动它,并且生成器将在结果可用时恢复。会有一些管理代码来保持生成器的运行。但这并没有多大帮助,因为生成器并不是跨浏览器的标准。

如果您有兴趣,这里有一篇关于使用生成器整理异步的 博客文章代码

Instead of writing helper methods like your fetch that return a value, make them accept another function, a "receiver", to pass their result to:

function fetch(receiver) {

    $.getJSON("blah...", function(data) {

        receiver(data);
    });
}

Obviously this is redundant because it's exactly how getJSON already works, but in a more realistic example the fetch function would process or filter the result somehow before passing it on.

Then instead of:

document.write(fetch());​

You'd do:

fetch(function(result) { document.write(result); });

Generators can be used to make asynchronous code a lot more linear in style. Each time you needed some asynchronous result, you'd yield a function to launch it, and the generator would resume when the result was available. There'd be a bit of management code keeping the generator going. But this isn't much help because generators are not standard across browsers.

If you're interested, here's a blog post about using generators to tidy up asynchronous code.

请你别敷衍 2024-08-28 05:41:10

JavaScript 语言有一个扩展,称为 StratifiedJS。它在每个浏览器中运行,并且允许您做到这一点:以同步/线性方式处理异步问题,而无需冻结浏览器。

您可以通过在网页中包含 Oni Apollo 来启用 Stratified JavaScript,例如:

<script src="http://code.onilabs.com/latest/oni-apollo.js"></script>
<script type="text/sjs"> your StratifiedJS code here </script>

您的代码如下所示:

function fetch() {  
  return require("http").jsonp(
    "http://api.flickr.com/services/feeds/photos_public.gne?" +
    "tags=cat&tagmode=any&format=json", {cbfield:"jsoncallback"});
}
document.write(fetch());​

或者,如果您确实想在 StratifiedJS 中使用 jQuery:

require("jquery-binding").install();
function fetch() {  
  var url = "http://api.flickr.com/?format=json&...&jsoncallback=?"
  return $.$getJSON(url);
}
document.write(fetch());​

文档位于 http://onilabs.com/docs

There is an extension to the JavaScript language called StratifiedJS. It runs in every browser, and it allows you to do just that: handling asynchronous problems in a synchronous/linear way without freezing your browser.

You can enable Stratified JavaScript e.g. by including Oni Apollo in your webpage like:

<script src="http://code.onilabs.com/latest/oni-apollo.js"></script>
<script type="text/sjs"> your StratifiedJS code here </script>

And your code would look like:

function fetch() {  
  return require("http").jsonp(
    "http://api.flickr.com/services/feeds/photos_public.gne?" +
    "tags=cat&tagmode=any&format=json", {cbfield:"jsoncallback"});
}
document.write(fetch());​

Or if you really want to use jQuery in StratifiedJS:

require("jquery-binding").install();
function fetch() {  
  var url = "http://api.flickr.com/?format=json&...&jsoncallback=?"
  return $.$getJSON(url);
}
document.write(fetch());​

The docs are on http://onilabs.com/docs

蛮可爱 2024-08-28 05:41:10

TameJS 库就是为了解决这个问题而设计的。

你可能会写一些类似的东西(未经测试):

var result = 'snap!';
await {
    $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", defer(result));
}
return result;

The TameJS library is designed to deal with this problem.

You might write something like (untested):

var result = 'snap!';
await {
    $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", defer(result));
}
return result;
半窗疏影 2024-08-28 05:41:10

jQuery 的下层 $.ajax() 函数 有更多选项,包括 async: [true|false] (默认为 true)。

尽管如此,在大多数情况下,您应该遵循 Ben 的建议并“接受语言的异步特性”。

The lower-level $.ajax() function from jQuery has more options, including async: [true|false] (default is true).

Nevertheless, in most cases you should follow Ben's advice and "embrace the async nature of the language".

固执像三岁 2024-08-28 05:41:10

我知道这一点有点晚了,但你可以在异步函数中使用 Promise 和等待来避免回调

deliverResult = (options) => (
  new Promise( (resolve, reject) => {
    $.ajax(options).done(resolve).fail(reject);
  })
)

getResult = async () => {
  let options = {
    type: 'get', 
    url: 'http://yourUrl.com', 
    data: {param1: 'arg1'}
  }
  console.log('waiting ..... ');
  let result = await deliverResult(options);
  console.log('**..waiting ended..**');
  console.log(result);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='button' onclick='getResult()' value='click me'/>

I know this a little late but you can avoid callbacks with promises and await in async function

deliverResult = (options) => (
  new Promise( (resolve, reject) => {
    $.ajax(options).done(resolve).fail(reject);
  })
)

getResult = async () => {
  let options = {
    type: 'get', 
    url: 'http://yourUrl.com', 
    data: {param1: 'arg1'}
  }
  console.log('waiting ..... ');
  let result = await deliverResult(options);
  console.log('**..waiting ended..**');
  console.log(result);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='button' onclick='getResult()' value='click me'/>

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