Bagaimana saya harus memanggil 3 fungsi untuk menjalankannya satu demi satu?

151

Jika saya perlu memanggil fungsi ini satu demi satu,

$('#art1').animate({'width':'1000px'},1000);        
$('#art2').animate({'width':'1000px'},1000);        
$('#art3').animate({'width':'1000px'},1000);        

Saya tahu di jQuery saya bisa melakukan sesuatu seperti:

$('#art1').animate({'width':'1000px'},1000,'linear',function(){
    $('#art2').animate({'width':'1000px'},1000,'linear',function(){
        $('#art3').animate({'width':'1000px'},1000);        
    });        
});        

Tapi, mari kita asumsikan bahwa saya tidak menggunakan jQuery dan saya ingin menelepon:

some_3secs_function(some_value);        
some_5secs_function(some_value);        
some_8secs_function(some_value);        

Bagaimana saya harus memanggil fungsi ini untuk mengeksekusi some_3secs_function, dan SETELAH panggilan itu berakhir, kemudian jalankan some_5secs_functiondan SETELAH panggilan itu berakhir, kemudian panggil some_8secs_function?

MEMPERBARUI:

Ini masih tidak berfungsi:

(function(callback){
    $('#art1').animate({'width':'1000px'},1000);
    callback();
})((function(callback2){
    $('#art2').animate({'width':'1000px'},1000);
    callback2();
})(function(){
    $('#art3').animate({'width':'1000px'},1000);
}));

Tiga animasi dimulai pada waktu yang bersamaan

Di mana kesalahan saya?

texai
sumber
maksud Anda fungsi dipanggil tepat 3 5 & 8 detik atau hanya satu demi satu?
Trass Vasston
Saya pikir Anda tidak yakin tentang eksekusi fungsi sinkron dan asinkron. Saya telah memperbarui jawaban saya di bawah ini. Semoga ini bisa membantu.
Wayne
Coba ini .. github.com/dineshkani24/queuecall
Dineshkani

Jawaban:

243

Di Javascript, ada yang sinkron dan asinkron fungsi .

Fungsi Sinkron

Sebagian besar fungsi dalam Javascript bersifat sinkron. Jika Anda memanggil beberapa fungsi sinkron berturut-turut

doSomething();
doSomethingElse();
doSomethingUsefulThisTime();

mereka akan mengeksekusi secara berurutan. doSomethingElsetidak akan mulai sampai doSomethingselesai. doSomethingUsefulThisTime, pada gilirannya, tidak akan mulai sampai doSomethingElseselesai.

Fungsi Asinkron

Fungsi asinkron, bagaimanapun, tidak akan menunggu satu sama lain. Mari kita lihat contoh kode yang sama dengan yang kita miliki di atas, kali ini dengan asumsi bahwa fungsinya tidak sinkron

doSomething();
doSomethingElse();
doSomethingUsefulThisTime();

Fungsi-fungsi akan diinisialisasi secara berurutan, tetapi semuanya akan dieksekusi secara kasar pada saat yang sama. Anda tidak dapat secara konsisten memprediksi yang mana yang akan selesai lebih dulu: yang terjadi untuk mengambil jumlah waktu terpendek untuk mengeksekusi akan selesai terlebih dahulu.

Tetapi kadang-kadang, Anda ingin menjalankan fungsi yang tidak sinkron secara berurutan, dan kadang-kadang Anda ingin fungsi yang sinkron dijalankan secara tidak sinkron. Untungnya, ini dimungkinkan dengan callback dan timeout, masing-masing.

Telepon balik

Mari kita asumsikan bahwa kita memiliki tiga fungsi asynchronous bahwa kita ingin mengeksekusi dalam rangka, some_3secs_function, some_5secs_function, dan some_8secs_function.

Karena fungsi dapat diteruskan sebagai argumen dalam Javascript, Anda bisa meneruskan fungsi sebagai panggilan balik untuk dieksekusi setelah fungsi selesai.

Jika kita membuat fungsi seperti ini

function some_3secs_function(value, callback){
  //do stuff
  callback();
}

maka Anda dapat menghubungi secara berurutan, seperti ini:

some_3secs_function(some_value, function() {
  some_5secs_function(other_value, function() {
    some_8secs_function(third_value, function() {
      //All three functions have completed, in order.
    });
  });
});

Batas waktu

Di Javascript, Anda bisa memberi tahu fungsi untuk dijalankan setelah batas waktu tertentu (dalam milidetik). Ini dapat, pada dasarnya, membuat fungsi sinkron berperilaku tidak sinkron.

Jika kita memiliki tiga fungsi sinkron, kita dapat menjalankannya secara tidak sinkron menggunakan setTimeoutfungsi tersebut.

setTimeout(doSomething, 10);
setTimeout(doSomethingElse, 10);
setTimeout(doSomethingUsefulThisTime, 10);

Namun, ini agak jelek dan melanggar prinsip KERING [wikipedia] . Kita bisa membersihkan ini sedikit dengan membuat fungsi yang menerima larik fungsi dan batas waktu.

function executeAsynchronously(functions, timeout) {
  for(var i = 0; i < functions.length; i++) {
    setTimeout(functions[i], timeout);
  }
}

Ini bisa disebut seperti ini:

executeAsynchronously(
    [doSomething, doSomethingElse, doSomethingUsefulThisTime], 10);

Singkatnya, jika Anda memiliki fungsi asinkron yang ingin Anda jalankan secara sinkron, gunakan panggilan balik, dan jika Anda memiliki fungsi sinkron yang ingin Anda jalankan secara tidak sinkron, gunakan timeout.

Peter Olson
sumber
7
Ini tidak akan menunda fungsi selama 3,5 dan 8 detik, seperti yang disarankan oleh contoh, mereka hanya akan berjalan satu demi satu.
Trass Vasston
1
@ Peter - Tunggu, jadi saya bingung. Jika ini adalah panggilan sinkron sederhana yang perlu waktu beberapa detik untuk diselesaikan, lalu mengapa kita memerlukan semua ini?
Wayne
9
@ Peter - +1 untuk metode paling indah dan berbelit-belit yang pernah saya lihat untuk memanggil tiga fungsi sinkron secara berurutan.
Wayne
4
Terima kasih karena telah menjelaskan perbedaan antara fungsi async dan sinkronisasi js. Ini menjelaskan banyak hal.
jnelson
2
Ini BUKAN benar karena alasan berikut: (1) 3 timeout semua akan menyelesaikan setelah 10 detik, sehingga semua 3 baris memicu pada waktu yang sama. (2) metode ini mengharuskan Anda untuk mengetahui durasi sebelumnya dan "jadwal" fungsi terjadi di masa depan, alih-alih menunggu fungsi async sebelumnya dalam rantai untuk menyelesaikan dan yang menjadi pemicunya. --- alih-alih Anda ingin menggunakan salah satu jawaban berikut menggunakan callback, janji, atau pustaka async.
zeroasterisk
37

Jawaban ini menggunakan promises, fitur JavaScript ECMAScript 6standar. Jika platform target Anda tidak mendukung promises, isi dengan PromiseJs .

Lihat jawaban saya di sini. Tunggu hingga Fungsi dengan animasi selesai hingga menjalankan Fungsi lainnya jika Anda ingin menggunakan jQueryanimasi.

Inilah kode Anda akan terlihat dengan ES6 Promisesdan jQuery animations.

Promise.resolve($('#art1').animate({ 'width': '1000px' }, 1000).promise()).then(function(){
    return Promise.resolve($('#art2').animate({ 'width': '1000px' }, 1000).promise());
}).then(function(){
    return Promise.resolve($('#art3').animate({ 'width': '1000px' }, 1000).promise());
});

Metode normal juga dapat dibungkus Promises.

new Promise(function(fulfill, reject){
    //do something for 5 seconds
    fulfill(result);
}).then(function(result){
    return new Promise(function(fulfill, reject){
        //do something for 5 seconds
        fulfill(result);
    });
}).then(function(result){
    return new Promise(function(fulfill, reject){
        //do something for 8 seconds
        fulfill(result);
    });
}).then(function(result){
    //do something with the result
});

The thenMetode dijalankan segera setelah Promiseselesai. Biasanya, nilai pengembalian yang functionditeruskan ke thenditeruskan ke yang berikutnya sebagai hasilnya.

Tetapi jika a Promisedikembalikan, thenfungsi berikutnya menunggu sampai Promiseselesai dieksekusi dan menerima hasilnya (nilai yang diteruskan ke fulfill).

Domysee
sumber
Saya tahu ini berguna, tetapi menemukan kode yang diberikan sulit dipahami tanpa mencari contoh dunia nyata untuk memberikan beberapa konteks. Saya menemukan video ini di YouTube: youtube.com/watch?v=y5mltEaQxa0 - dan menulis sumber dari video di sini drive.google.com/file/d/1NrsAYs1oaxXw0kv9hz7a6LjtOEb6x7z-/… Ada beberapa lagi nuansa seperti tangkapan yang hilang di contoh ini diuraikan di sini. (gunakan id lain di baris getPostById () atau coba ubah nama penulis sehingga tidak cocok dengan pos, dll.)
JGFMK
20

Sepertinya Anda tidak sepenuhnya menghargai perbedaan antara eksekusi fungsi sinkron dan asinkron .

Kode yang Anda berikan dalam pembaruan Anda segera menjalankan setiap fungsi panggilan balik Anda, yang pada gilirannya segera memulai animasi. Animasi, bagaimanapun, mengeksekusi asyncronously . Ini berfungsi seperti ini:

  1. Lakukan langkah dalam animasi
  2. Panggil setTimeoutdengan fungsi yang berisi langkah animasi berikutnya dan penundaan
  3. Beberapa waktu berlalu
  4. Callback yang diberikan untuk setTimeoutdieksekusi
  5. Kembali ke langkah 1

Ini berlanjut sampai langkah terakhir dalam animasi selesai. Sementara itu, fungsi sinkron Anda sudah lama diselesaikan. Dengan kata lain, panggilan Anda ke animatefungsi tidak benar - benar membutuhkan waktu 3 detik. Efeknya disimulasikan dengan penundaan dan panggilan balik.

Yang Anda butuhkan adalah antrian . Secara internal, jQuery antrian animasi, hanya mengeksekusi Anda panggilan balik setelah animasi yang sesuai selesai. Jika panggilan balik Anda kemudian memulai animasi lain, efeknya adalah mereka dieksekusi secara berurutan.

Dalam kasus paling sederhana ini setara dengan yang berikut:

window.setTimeout(function() {
    alert("!");
    // set another timeout once the first completes
    window.setTimeout(function() {
        alert("!!");
    }, 1000);
}, 3000); // longer, but first

Berikut adalah fungsi perulangan asinkron umum. Ini akan memanggil fungsi yang diberikan secara berurutan, menunggu jumlah detik yang ditentukan antara masing-masing.

function loop() {
    var args = arguments;
    if (args.length <= 0)
        return;
    (function chain(i) {
        if (i >= args.length || typeof args[i] !== 'function')
            return;
        window.setTimeout(function() {
            args[i]();
            chain(i + 1);
        }, 2000);
    })(0);
}    

Pemakaian:

loop(
  function() { alert("sam"); }, 
  function() { alert("sue"); });

Anda jelas dapat memodifikasi ini untuk mengambil waktu tunggu yang dapat dikonfigurasi atau untuk segera menjalankan fungsi pertama atau untuk berhenti mengeksekusi ketika fungsi dalam rantai kembali falseatau ke applyfungsi dalam konteks tertentu atau apa pun yang Anda butuhkan.

Wayne
sumber
14

Saya percaya perpustakaan async akan memberi Anda cara yang sangat elegan untuk melakukan ini. Sementara janji dan panggilan balik bisa sedikit sulit untuk ditangani, async dapat memberikan pola yang rapi untuk merampingkan proses pemikiran Anda. Untuk menjalankan fungsi secara serial, Anda harus meletakkannya di air terjun async . Dalam async lingo, setiap fungsi disebut a taskyang mengambil beberapa argumen dan a callback; yang merupakan fungsi selanjutnya dalam urutan. Struktur dasar akan terlihat seperti:

async.waterfall([
  // A list of functions
  function(callback){
      // Function no. 1 in sequence
      callback(null, arg);
  },
  function(arg, callback){
      // Function no. 2 in sequence
      callback(null);
  }
],    
function(err, results){
   // Optional final callback will get results for all prior functions
});

Saya baru saja mencoba menjelaskan struktur secara singkat di sini. Bacalah panduan air terjun untuk informasi lebih lanjut, ini ditulis dengan cukup baik.

Ali
sumber
1
Ini benar-benar membuat JS sedikit lebih tertahankan.
Mike
9

fungsi Anda harus menggunakan fungsi panggilan balik, yang dipanggil saat selesai.

function fone(callback){
...do something...
callback.apply(this,[]);

}

function ftwo(callback){
...do something...
callback.apply(this,[]);
}

maka penggunaannya akan seperti:

fone(function(){
  ftwo(function(){
   ..ftwo done...
  })
});
pengguna406905
sumber
4
asec=1000; 

setTimeout('some_3secs_function("somevalue")',asec*3);
setTimeout('some_5secs_function("somevalue")',asec*5);
setTimeout('some_8secs_function("somevalue")',asec*8);

Saya tidak akan membahas diskusi mendalam tentang setTimeout di sini, tetapi:

  • dalam hal ini saya telah menambahkan kode untuk dieksekusi sebagai string. ini adalah cara paling sederhana untuk melewatkan var ke fungsi setTimeout-ed Anda, tetapi pembuat puritan akan mengeluh.
  • Anda juga dapat memberikan nama fungsi tanpa tanda kutip, tetapi tidak ada variabel yang dapat dikirimkan.
  • kode Anda tidak menunggu setTimeout untuk memicu.
  • Yang ini bisa sulit untuk membuat kepala Anda di sekitar pada awalnya: karena titik sebelumnya, jika Anda melewati variabel dari fungsi panggilan Anda, variabel itu tidak akan ada lagi pada saat batas waktu memicu - fungsi panggilan akan dieksekusi dan itu vars pergi.
  • Saya telah diketahui menggunakan fungsi anonim untuk mengatasi semua ini, tetapi mungkin ada cara yang lebih baik,
Trass Vasston
sumber
3

Karena Anda menandai dengan javascript, saya akan pergi dengan kontrol timer karena nama fungsi Anda adalah 3, 5, dan 8 detik. Jadi mulai timer Anda, 3 detik masuk, panggilan pertama, 5 detik panggilan kedua, 8 detik panggilan ketiga, lalu setelah selesai, hentikan timer.

Biasanya dalam Javascript apa yang Anda miliki benar untuk fungsi berjalan satu demi satu, tetapi karena sepertinya Anda mencoba melakukan animasi waktunya, timer akan menjadi taruhan terbaik Anda.

Sorean
sumber
2

//sample01
(function(_){_[0]()})([
	function(){$('#art1').animate({'width':'10px'},100,this[1].bind(this))},
	function(){$('#art2').animate({'width':'10px'},100,this[2].bind(this))},
	function(){$('#art3').animate({'width':'10px'},100)},
])

//sample02
(function(_){_.next=function(){_[++_.i].apply(_,arguments)},_[_.i=0]()})([
	function(){$('#art1').animate({'width':'10px'},100,this.next)},
	function(){$('#art2').animate({'width':'10px'},100,this.next)},
	function(){$('#art3').animate({'width':'10px'},100)},
]);

//sample03
(function(_){_.next=function(){return _[++_.i].bind(_)},_[_.i=0]()})([
	function(){$('#art1').animate({'width':'10px'},100,this.next())},
	function(){$('#art2').animate({'width':'10px'},100,this.next())},
	function(){$('#art3').animate({'width':'10px'},100)},
]);

yuuya
sumber
Bisakah Anda jelaskan apa ini? Apa yang terikat pada garis bawah? Apa fungsi yang ditugaskan nextlakukan?
mtso
1
Saya menjelaskan sampel 2 dengan menggunakan jsfiddle. jsfiddle.net/mzsteyuy/3 Jika Anda mengizinkan saya untuk menjelaskan secara kasar, contoh 2 adalah cara singkat dari kode di jsfiddle. garis bawah adalah Array yang elemen-elemennya adalah counter valiable (i) dan berfungsi berikutnya dan berfungsi [0] ~ [2].
yuuya
1

Anda juga bisa menggunakan janji dengan cara ini:

    some_3secs_function(this.some_value).then(function(){
       some_5secs_function(this.some_other_value).then(function(){
          some_8secs_function(this.some_other_other_value);
       });
    });

Anda harus membuat some_valueglobal untuk mengaksesnya dari dalam. Maka

Atau, dari fungsi luar Anda bisa mengembalikan nilai yang akan digunakan fungsi dalam, seperti:

    one(some_value).then(function(return_of_one){
       two(return_of_one).then(function(return_of_two){
          three(return_of_two);
       });
    });
Cuzox
sumber
0

Saya menggunakan fungsi 'waitUntil' berdasarkan setTimeout javascript

/*
    funcCond : function to call to check whether a condition is true
    readyAction : function to call when the condition was true
    checkInterval : interval to poll <optional>
    timeout : timeout until the setTimeout should stop polling (not 100% accurate. It was accurate enough for my code, but if you need exact milliseconds, please refrain from using Date <optional>
    timeoutfunc : function to call on timeout <optional>
*/
function waitUntil(funcCond, readyAction, checkInterval, timeout, timeoutfunc) {
    if (checkInterval == null) {
        checkInterval = 100; // checkinterval of 100ms by default
    }
    var start = +new Date(); // use the + to convert it to a number immediatly
    if (timeout == null) {
        timeout = Number.POSITIVE_INFINITY; // no timeout by default
    }
    var checkFunc = function() {
        var end = +new Date(); // rough timeout estimations by default

        if (end-start > timeout) {
            if (timeoutfunc){ // if timeout function was defined
                timeoutfunc(); // call timeout function
            }
        } else {
            if(funcCond()) { // if condition was met
                readyAction(); // perform ready action function
            } else {
                setTimeout(checkFunc, checkInterval); // else re-iterate
            }
        }
    };
    checkFunc(); // start check function initially
};

Ini akan bekerja dengan sempurna jika fungsi Anda menetapkan kondisi tertentu menjadi true, yang dapat Anda polling. Ditambah lagi dengan timeout, yang menawarkan Anda alternatif jika fungsi Anda gagal melakukan sesuatu (bahkan dalam rentang waktu. Pikirkan tentang umpan balik pengguna!)

misalnya

doSomething();
waitUntil(function() { return doSomething_value===1;}, doSomethingElse);
waitUntil(function() { return doSomethingElse_value===1;}, doSomethingUseful);

Catatan

Tanggal menyebabkan perkiraan batas waktu kasar. Untuk presisi yang lebih besar, beralihlah ke fungsi-fungsi seperti console.time (). Perhatikan bahwa Date menawarkan dukungan lintas-browser dan warisan yang lebih besar. Jika Anda tidak membutuhkan pengukuran milidetik yang tepat; jangan repot-repot, atau, kalau tidak, bungkus, dan tawarkan console.time () ketika browser mendukungnya

Biepbot Von Stirling
sumber
0

Jika metode 1 harus dijalankan setelah metode 2, 3, 4. Cuplikan kode berikut dapat menjadi solusi untuk ini menggunakan objek Ditangguhkan dalam JavaScript.

function method1(){
  var dfd = new $.Deferred();
     setTimeout(function(){
     console.log("Inside Method - 1"); 
     method2(dfd);	 
    }, 5000);
  return dfd.promise();
}

function method2(dfd){
  setTimeout(function(){
   console.log("Inside Method - 2"); 
   method3(dfd);	
  }, 3000);
}

function method3(dfd){
  setTimeout(function(){
   console.log("Inside Method - 3"); 	
   dfd.resolve();
  }, 3000);
}

function method4(){   
   console.log("Inside Method - 4"); 	
}

var call = method1();

$.when(call).then(function(cb){
  method4();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Sahadeb Patro
sumber