Rumah >hujung hadapan web >tutorial js >Konsep asas tak segerak dan panggil balik dalam JavaScript dan fenomena neraka panggil balik

Konsep asas tak segerak dan panggil balik dalam JavaScript dan fenomena neraka panggil balik

WBOY
WBOYke hadapan
2022-08-17 18:05:251682semak imbas

Artikel ini membawakan anda pengetahuan yang berkaitan tentang javascript Ia terutamanya memperkenalkan konsep asas tak segerak dan panggil balik dalam JavaScript, serta fenomena neraka panggil balik Artikel ini terutamanya memperkenalkan konsep asas tak segerak dan panggilan balik, kedua-duanya adalah kandungan teras JavaScript. Saya harap ia akan membantu semua orang.

Konsep asas tak segerak dan panggil balik dalam JavaScript dan fenomena neraka panggil balik

[Cadangan berkaitan: tutorial video javascript, bahagian hadapan web]

JavaScript tak segerak dan panggil balik

1. Pengenalan

Sebelum mengkaji kandungan artikel ini, kita mesti memahami konsep tak segerak Perkara pertama yang perlu ditekankan ialah Ada perbezaan penting antara tak segerak dan selari.

  • Selari, secara amnya merujuk kepada pengkomputeran selari, yang bermaksud bahawa berbilang arahan dilaksanakan pada masa yang sama Arahan ini boleh dilaksanakan pada CPU berbilang teras atau berbilang CPU yang sama. , atau Berbilang hos fizikal atau malah berbilang rangkaian.
  • Penyegerakan secara amnya merujuk kepada melaksanakan tugas dalam susunan yang telah ditetapkan Hanya apabila tugasan sebelumnya selesai, tugasan seterusnya akan dilaksanakan.
  • Asynchronous, sepadan dengan penyegerakan, asynchronous bermaksud untuk membiarkan CPU menahan sementara tugas semasa, memproses tugas seterusnya dahulu, dan kemudian kembali ke tugas sebelumnya untuk meneruskan pelaksanaan selepas menerima pemberitahuan panggilan balik tugas sebelumnya. ,Seluruh proses tidak memerlukan penyertaan urutan kedua.

Mungkin adalah lebih intuitif untuk menggunakan gambar untuk menerangkan keselarian, penyegerakan dan ketaksegerakan. Andaikan terdapat dua tugasan A dan B yang perlu diproses iaitu kaedah pemprosesan selari, segerak dan tak segerak seperti berikut: Kaedah pelaksanaan yang ditunjukkan:

2. Fungsi tak segerak

JavaScript memberikan kita banyak fungsi tak segerak, ini Fungsi membolehkan kami melaksanakan tugas tak segerak dengan mudah Maksudnya, kami mula melaksanakan tugas (fungsi) sekarang, tetapi tugas itu akan diselesaikan kemudian, dan masa penyiapan khusus tidak jelas.

Sebagai contoh, fungsi setTimeout ialah fungsi tak segerak yang sangat tipikal, fs.readFile dan fs.writeFile juga merupakan fungsi tak segerak.

Kami boleh menentukan sendiri kes tugas tak segerak, seperti menyesuaikan fungsi salinan fail copyFile(from,to):

const fs = require('fs')

function copyFile(from, to) {
    fs.readFile(from, (err, data) => {
        if (err) {
            console.log(err.message)
            return
        }
        fs.writeFile(to, data, (err) => {
            if (err) {
                console.log(err.message)
                return
            }
            console.log('Copy finished')
        })
    })
}

Fungsi copyFile membaca data fail daripada parameter , dan kemudian menulis data ke fail yang ditunjuk oleh parameter from. to

Kita boleh memanggil

seperti ini: copyFile

copyFile('./from.txt','./to.txt')//复制文件
Jika terdapat kod lain selepas

pada masa ini, program tidak akan menunggu selesai copyFile(...) pelaksanaan , tetapi Laksanakan secara langsung, program tidak peduli apabila tugas penyalinan fail tamat. copyFile

copyFile('./from.txt','./to.txt')
//下面的代码不会等待上面的代码执行结束
...
Pada ketika ini, semuanya kelihatan seperti biasa Namun, apakah yang akan berlaku jika kita terus mengakses kandungan fail

selepas fungsi copyFile(...)? ./to.txt

Ini tidak akan membaca kandungan yang disalin, seperti ini:

copyFile('./from.txt','./to.txt')
fs.readFile('./to.txt',(err,data)=>{
    ...
})
Jika fail

belum dibuat sebelum melaksanakan program, anda akan mendapat ralat berikut: ./to.txt

PS E:CodeNodedemos

PS E:\Code\Node\demos\03-callback> node .\index.js
Copy finished
加入社区“仙宗”,和我一起修仙吧
社区地址:http://t.csdn.cn/EKf1h

这种编程方式被称为“基于回调”的异步编程风格,异步执行的函数应当提供一个回调参数用于在任务结束后调用。

这种风格在JavaScript编程中普遍存在,例如文件读取函数fs.readFilefs.writeFile都是异步函数。

四、回调的回调

回调函数可以准确的在异步工作完成后处理后继事宜,如果我们需要依次执行多个异步操作,就需要嵌套回调函数。

案例场景:依次读取文件A和文件B

代码实现:

fs.readFile('./A.txt', (err, data) => {
    if (err) {
        console.log(err.message)
        return
    }
    console.log('读取文件A:' + data.toString())
    fs.readFile('./B.txt', (err, data) => {
        if (err) {
            console.log(err.message)
            return
        }
        console.log("读取文件B:" + data.toString())
    })
})

执行效果:

PS E:\Code\Node\demos\03-callback> node .\index.js
读取文件A:仙宗无限好,只是缺了佬

读取文件B:要想入仙宗,链接不能少  
http://t.csdn.cn/H1faI

通过回调的方式,就可以在读取文件A之后,紧接着读取文件B。

如果我们还想在文件B之后,继续读取文件C呢?这就需要继续嵌套回调:

fs.readFile('./A.txt', (err, data) => {//第一次回调
    if (err) {
        console.log(err.message)
        return
    }
    console.log('读取文件A:' + data.toString())
    fs.readFile('./B.txt', (err, data) => {//第二次回调
        if (err) {
            console.log(err.message)
            return
        }
        console.log("读取文件B:" + data.toString())
        fs.readFile('./C.txt',(err,data)=>{//第三次回调
            ...
        })
    })
})

也就是说,如果我们想要依次执行多个异步操作,需要多层嵌套回调,这在层数较少时是行之有效的,但是当嵌套次数过多时,会出现一些问题。

回调的约定

实际上,fs.readFile中的回调函数的样式并非个例,而是JavaScript中的普遍约定。我们日后会自定义大量的回调函数,也需要遵守这种约定,形成良好的编码习惯。

约定是:

  • callback 的第一个参数是为 error 而保留的。一旦出现 error,callback(err) 就会被调用。
  • 第二个以及后面的参数用于接收异步操作的成功结果。此时 callback(null, result1, result2,...) 就会被调用。

基于以上约定,一个回调函数拥有错误处理和结果接收两个功能,例如fs.readFile('...',(err,data)=>{})的回调函数就遵循了这种约定。

五、回调地狱

如果我们不深究的话,基于回调的异步方法处理似乎是相当完美的处理方式。问题在于,如果我们有一个接一个 的异步行为,那么代码就会变成这样:

fs.readFile('./a.txt',(err,data)=>{
    if(err){
        console.log(err.message)
        return
    }
    //读取结果操作
    fs.readFile('./b.txt',(err,data)=>{
        if(err){
            console.log(err.message)
            return
        }
        //读取结果操作
        fs.readFile('./c.txt',(err,data)=>{
            if(err){
                console.log(err.message)
                return
            }
            //读取结果操作
            fs.readFile('./d.txt',(err,data)=>{
                if(err){
                    console.log(err.message)
                    return
                }
                ...
            })
        })
    })
})

以上代码的执行内容是:

  • 读取文件a.txt,如果没有发生错误的话;
  • 读取文件b.txt,如果没有发生错误的话;
  • 读取文件c.txt,如果没有发生错误的话;
  • 读取文件d.txt,…

随着调用的增加,代码嵌套层级越来越深,包含越来越多的条件语句,从而形成不断向右缩进的混乱代码,难以阅读和维护。

我们称这种不断向右增长(向右缩进)的现象为“回调地狱”或者“末日金字塔”!

fs.readFile('a.txt',(err,data)=>{
    fs.readFile('b.txt',(err,data)=>{
        fs.readFile('c.txt',(err,data)=>{
            fs.readFile('d.txt',(err,data)=>{
                fs.readFile('e.txt',(err,data)=>{
                    fs.readFile('f.txt',(err,data)=>{
                        fs.readFile('g.txt',(err,data)=>{
                            fs.readFile('h.txt',(err,data)=>{
                                ...
                                /*
								  通往地狱的大门
								  ===>
                                */
                            })
                        })
                    })
                })
            })
        })
    })
})

虽然以上代码看起来相当规整,但是这只是用于举例的理想场面,通常业务逻辑中会有大量的条件语句、数据处理操作等代码,从而打乱当前美好的秩序,让代码变的难以维护。

幸运的是,JavaScript为我们提供了多种解决途径,Promise就是其中的最优解。

【相关推荐:javascript视频教程web前端

Atas ialah kandungan terperinci Konsep asas tak segerak dan panggil balik dalam JavaScript dan fenomena neraka panggil balik. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:jb51.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam