简体   繁体   English

JavaScript中的异步编程,没有混乱的回调

[英]Asynchronous programming in JavaScript without messy callbacks

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. 结果总是'snap!',因为$.getJSONfetch()完成后运行。

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. 在JS 1.7中读到了关于生成器和迭代器的内容 ,但我不知道如何将它应用于我的问题。

This question is not really about jQuery. 这个问题并不是关于jQuery的。 Instead of $.getJSON could be any another asynchronous function. 而不是$ .getJSON可以是任何其他异步函数。

See this question also: Halt JavaScript execution without locking up the browser 另请参阅此问题: 暂停JavaScript执行而不锁定浏览器

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. 例如,您可以选择在回调闭包内从不做任何实际工作,但为了清楚起见,只需调用另一个顶级函数/方法。

You want to roll your own $.getSyncJSON that uses $.ajax({async:false}). 您想要使用$ .ajax({async:false})滚动自己的$ .getSyncJSON。 See: http://api.jquery.com/jQuery.ajax/ . 请参阅: 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. 您可以轻松地锁定所有输入的浏览器,使您的UI受到网络的支配。 But if you know what you are doing and are sure of your use case, go for it. 但是如果你知道自己在做什么,并确定你的用例,那就去吧。

Instead of writing helper methods like your fetch that return a value, make them accept another function, a "receiver", to pass their result to: 而不是像你的fetch那样写一个返回值的辅助方法,让它们接受另一个函数,一个“接收器”,将它们的结果传递给:

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. 显然这是多余的,因为它正是getJSON工作方式,但在一个更现实的例子中, fetch函数会在传递之前以某种方式处理或过滤结果。

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 . 如果您有兴趣,这里有一篇关于使用生成器来整理异步代码博客文章

There is an extension to the JavaScript language called StratifiedJS. JavaScript语言的扩展名为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 eg by including Oni Apollo in your webpage like: 您可以启用分层JavaScript,例如在您的网页中包含Oni Apollo,例如:

<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: 或者如果你真的想在StratifiedJS中使用jQuery:

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 文档在http://onilabs.com/docs上

The TameJS library is designed to deal with this problem. TameJS库旨在解决此问题。

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;

The lower-level $.ajax() function from jQuery has more options, including async: [true|false] (default is true). jQuery中的低级$ .ajax()函数有更多选项,包括async: [true|false] (默认为true)。

Nevertheless, in most cases you should follow Ben's advice and "embrace the async nature of the language". 然而,在大多数情况下,你应该遵循Ben的建议并“接受语言的异步性质”。

I know this a little late but you can avoid callbacks with promises and await in async function 我知道这有点晚了但你可以避免使用promises回调并等待async函数

 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'/> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM