Подтвердить что ты не робот

Как создать асинхронную функцию в Javascript?

Я имею в виду, проверьте этот код:

<a href="#" id="link">Link</a>
<span>Moving</span>

$('#link').click(function () {
    console.log("Enter");
    $('#link').animate({ width: 200 }, 2000, function() {
         console.log("finished");            
    });    
    console.log("Exit");    
});

как вы можете видеть в консоли, функция "animate" является асинхронной, и она "развивает" поток блока кода обработчика события. Фактически:

$('#link').click(function () {
    console.log("Enter");
    asyncFunct();
    console.log("Exit");    
});

function asyncFunct() {
    console.log("finished");
}

следуйте потоку блочного кода!

Если я хочу создать мой function asyncFunct() { } с таким поведением, как я могу это сделать с помощью javascript/jquery? Я думаю, что существует стратегия без использования setTimeout()  

4b9b3361

Ответ 1

Вы не можете создать по-настоящему настраиваемую асинхронную функцию. В конечном итоге вам придется использовать технологию, предоставляемую изначально, например:

  • setInterval
  • setTimeout
  • requestAnimationFrame
  • XMLHttpRequest
  • WebSocket
  • Worker
  • Некоторые API-интерфейсы HTML5, такие как API файлов, API веб-баз данных
  • Технологии, поддерживающие onload
  • ... многие другие

Фактически, для анимации jQuery использует setInterval.

Ответ 2

Вы можете использовать таймер:

setTimeout( yourFn, 0 );

(где yourFn - ссылка на вашу функцию)

или, underscore.js:

_.defer( yourFn );

Защиты, вызывающие эту функцию, до тех пор, пока текущий стек вызовов не будет очищен, аналогично использованию setTimeout с задержкой 0. Полезно для выполнения дорогостоящие вычисления или рендеринг HTML в кусках без блокировки поток пользовательского интерфейса от обновления.

Ответ 3

здесь у вас есть простое решение (другие пишут об этом) http://www.benlesh.com/2012/05/calling-javascript-function.html

И здесь у вас есть готовое решение:

function async(your_function, callback) {
    setTimeout(function() {
        your_function();
        if (callback) {callback();}
    }, 0);
}

TEST 1 (может выводить '1 x 2 3' или '1 2 x 3' или '1 2 3 x'):

console.log(1);
async(function() {console.log('x')}, null);
console.log(2);
console.log(3);

TEST 2 (всегда будет выводить 'x 1'):

async(function() {console.log('x');}, function() {console.log(1);});

Эта функция выполняется с таймаутом 0 - она ​​будет имитировать асинхронную задачу

Ответ 4

Вот функция, которая принимает другую функцию и выводит версию, выполняющую async.

var async = function (func) {
  return function () {
    var args = arguments;
    setTimeout(function () {
      func.apply(this, args);
    }, 0);
  };
};

Он используется как простой способ сделать асинхронную функцию:

var anyncFunction = async(function (callback) {
    doSomething();
    callback();
});

Это отличается от ответа @fider, потому что сама функция имеет свою собственную структуру (никакой обратный вызов не добавлен, он уже находится в функции), а также потому, что он создает новую функцию, которая может быть использована.

Ответ 5

Эта страница позволяет ознакомиться с основами создания функции async javascript.

Выполнение асинхронных вызовов функций в JavaScript с использованием аргументов обычно включает в себя построение аргумента выражения для setTimeout или setInterval вручную.

Если это не поможет вам, ознакомьтесь с документацией по функции animate.

Ответ 6

Изменить: Я полностью не понял этот вопрос. В браузере я бы использовал setTimeout. Если было важно, чтобы он работал в другом потоке, я бы использовал "Веб-работники" .

Ответ 7

Если вы хотите использовать параметры и регулировать максимальное количество асинхронных функций, вы можете использовать простой рабочий async, который я создал:

var BackgroundWorker = function(maxTasks) {
    this.maxTasks = maxTasks || 100;
    this.runningTasks = 0;
    this.taskQueue = [];
};

/* runs an async task */
BackgroundWorker.prototype.runTask = function(task, delay, params) {
    var self = this;
    if(self.runningTasks >= self.maxTasks) {
        self.taskQueue.push({ task: task, delay: delay, params: params});
    } else {
        self.runningTasks += 1;
        var runnable = function(params) {
            try {
                task(params);
            } catch(err) {
                console.log(err);
            }
            self.taskCompleted();
        }
        // this approach uses current standards:
        setTimeout(runnable, delay, params);
    }
}

BackgroundWorker.prototype.taskCompleted = function() {
    this.runningTasks -= 1;

    // are any tasks waiting in queue?
    if(this.taskQueue.length > 0) {
        // it seems so! let run it x)
        var taskInfo = this.taskQueue.splice(0, 1)[0];
        this.runTask(taskInfo.task, taskInfo.delay, taskInfo.params);
    }
}

Вы можете использовать его следующим образом:

var myFunction = function() {
 ...
}
var myFunctionB = function() {
 ...
}
var myParams = { name: "John" };

var bgworker = new BackgroundWorker();
bgworker.runTask(myFunction, 0, myParams);
bgworker.runTask(myFunctionB, 0, null);

Ответ 8

Я вижу здесь, что никто не говорил об этом обещании. Поэтому я рекомендую вам узнать о обещании: посмотреть эту ссылку

Ответ 9

Function.prototype.applyAsync = function(params, cb){
      var function_context = this;
      setTimeout(function(){
          var val = function_context.apply(undefined, params); 
          if(cb) cb(val);
      }, 0);
}

// usage
var double = function(n){return 2*n;};
var display = function(){console.log(arguments); return undefined;};
double.applyAsync([3], display);

Хотя это не принципиально отличается от других решений, я думаю, что мое решение делает несколько дополнительных приятных вещей:

  • он позволяет параметрам выполнять функции
  • он передает выходные данные функции обратному вызову
  • добавляется к Function.prototype, позволяя более удобный способ его называть

Кроме того, мне кажется подобие встроенной функции Function.prototype.apply.

Ответ 10

К сожалению, JavaScript не предоставляет асинхронную функциональность. Он работает только в одном потоке. Но большинство современных браузеров предоставляют Worker s, которые являются вторыми скриптами, которые выполняются в фоновом режиме и могут возвращать результат. Итак, я достиг решения, которое, как мне кажется, полезно для асинхронного запуска функции, которая создает рабочего для каждого асинхронного вызова.

В приведенном ниже коде содержится функция async для вызова в фоновом режиме.

Function.prototype.async = function(callback) {
    let blob = new Blob([ "self.addEventListener('message', function(e) { self.postMessage({ result: (" + this + ").apply(null, e.data) }); }, false);" ], { type: "text/javascript" });
    let worker = new Worker(window.URL.createObjectURL(blob));
    worker.addEventListener("message", function(e) {
        this(e.data.result);
    }.bind(callback), false);
    return function() {
        this.postMessage(Array.from(arguments));
    }.bind(worker);
};

Это пример использования:

(function(x) {
    for (let i = 0; i < 999999999; i++) {}
        return x * 2;
}).async(function(result) {
    alert(result);
})(10);

Выполняет функцию, которая перебирает for с огромным числом, чтобы взять время как демонстрацию асинхронности, а затем получает двойное число прошедшего числа. Метод async предоставляет function, который вызывает нужную функцию в фоновом режиме, а в том, что предоставляется как параметр async, вызывает return в своем уникальном параметре. Таким образом, в функции обратного вызова я alert результат.

Ответ 11

В MDN есть хороший пример об использовании setTimeout, сохраняющего "this".

Как показано ниже:

function doSomething() {
    // use 'this' to handle the selected element here
}

$(".someSelector").each(function() {
    setTimeout(doSomething.bind(this), 0);
});

Ответ 12

Рядом с большим ответом от @pimvdb, и на всякий случай, когда вам интересно, async.js не предлагает действительно асинхронных функций либо, Вот (очень) урезанная версия основного метода библиотеки:

function asyncify(func) { // signature: func(array)
    return function (array, callback) {
        var result;
        try {
            result = func.apply(this, array);
        } catch (e) {
            return callback(e);
        }
        /* code ommited in case func returns a promise */
        callback(null, result);
    };
}

Таким образом, функция защищает от ошибок и изящно передает ее обратному вызову, но код такой же синхронный, как и любая другая функция JS.