nodeJs callbacks ตัวอย่างง่ายๆ


120

ใครช่วยยกตัวอย่างง่ายๆของการเรียกกลับ nodeJs ฉันได้ค้นหาสิ่งเดียวกันนี้ในหลายเว็บไซต์ แต่ไม่สามารถเข้าใจได้อย่างถูกต้องโปรดยกตัวอย่างง่ายๆให้ฉัน

getDbFiles(store, function(files){
    getCdnFiles(store, function(files){
    })
})

ฉันอยากทำอะไรแบบนั้น ...


ตัวอย่างวิธีการเขียนฟังก์ชันที่ใช้การเรียกกลับเป็นอาร์กิวเมนต์?
Gntem

ใช่อะไรทำนองนั้นตัวอย่างง่ายๆที่ช่วยให้ฉันเข้าใจ
Bhushan Goel

2
การเรียกกลับเป็นฟังก์ชันที่คุณส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันอื่น ... Google pls -> "callback javascript" -> ผลลัพธ์แรก
Gabriel Llamas

คำตอบ:


198
var myCallback = function(data) {
  console.log('got data: '+data);
};

var usingItNow = function(callback) {
  callback('get it?');
};

ตอนนี้เปิดโหนดหรือคอนโซลเบราว์เซอร์และวางคำจำกัดความข้างต้น

สุดท้ายใช้กับบรรทัดถัดไปนี้:

usingItNow(myCallback);

ด้วยความเคารพต่อข้อตกลงข้อผิดพลาดสไตล์โหนด

คอสตาถามว่าสิ่งนี้จะเป็นอย่างไรหากเราให้เกียรติกับข้อตกลงการเรียกกลับโหนด

ในหลักการนี้การเรียกกลับควรคาดหวังว่าจะได้รับอย่างน้อยหนึ่งอาร์กิวเมนต์ซึ่งเป็นอาร์กิวเมนต์แรกเป็นข้อผิดพลาด ทางเลือกที่เราจะมีอาร์กิวเมนต์เพิ่มเติมอย่างน้อยหนึ่งข้อขึ้นอยู่กับบริบท ในกรณีนี้บริบทคือตัวอย่างข้างต้นของเรา

ฉันเขียนตัวอย่างของเราใหม่ในอนุสัญญานี้

var myCallback = function(err, data) {
  if (err) throw err; // Check for the error and throw if it exists.
  console.log('got data: '+data); // Otherwise proceed as usual.
};

var usingItNow = function(callback) {
  callback(null, 'get it?'); // I dont want to throw an error, so I pass null for the error argument
};

หากเราต้องการจำลองกรณีข้อผิดพลาดเราสามารถกำหนดโดยใช้ItNowเช่นนี้

var usingItNow = function(callback) {
  var myError = new Error('My custom error!');
  callback(myError, 'get it?'); // I send my error as the first argument.
};

การใช้งานขั้นสุดท้ายเหมือนกับในด้านบน:

usingItNow(myCallback);

ความแตกต่างเพียงอย่างเดียวในพฤติกรรมจะขึ้นอยู่กับเวอร์ชันที่usingItNowคุณได้กำหนดไว้: อันที่ฟีด "ค่าที่แท้จริง" (วัตถุข้อผิดพลาด) ไปยังการเรียกกลับสำหรับอาร์กิวเมนต์แรกหรือค่าที่ป้อนค่าว่างสำหรับอาร์กิวเมนต์ข้อผิดพลาด .


แล้วสิ่งนี้จะเป็นอย่างไรเมื่อข้อผิดพลาดเป็นอนุสัญญาพารามิเตอร์แรก?
Costa

113

ฟังก์ชันเรียกกลับเป็นเพียงฟังก์ชันที่คุณส่งผ่านไปยังฟังก์ชันอื่นเพื่อให้ฟังก์ชันนั้นสามารถเรียกใช้ในภายหลังได้ นี้มีให้เห็นกันทั่วไปในตรงกันAPI s; การเรียก API จะส่งกลับทันทีเนื่องจากเป็นแบบอะซิงโครนัสดังนั้นคุณจึงส่งผ่านฟังก์ชันเข้าไปในนั้นซึ่ง API สามารถเรียกใช้เมื่อดำเนินการทำงานแบบอะซิงโครนัสเสร็จแล้ว

ตัวอย่างที่ง่ายที่สุดที่ฉันคิดได้ใน JavaScript คือsetTimeout()ฟังก์ชัน เป็นฟังก์ชันส่วนกลางที่ยอมรับสองอาร์กิวเมนต์ อาร์กิวเมนต์แรกคือฟังก์ชันเรียกกลับและอาร์กิวเมนต์ที่สองคือความล่าช้าในหน่วยมิลลิวินาที ฟังก์ชันนี้ออกแบบมาเพื่อรอระยะเวลาที่เหมาะสมจากนั้นเรียกใช้ฟังก์ชันเรียกกลับของคุณ

setTimeout(function () {
  console.log("10 seconds later...");
}, 10000);

คุณอาจเคยเห็นรหัสด้านบนมาก่อน แต่ไม่ทราบว่าฟังก์ชันที่คุณส่งผ่านนั้นเรียกว่าฟังก์ชันเรียกกลับ เราสามารถเขียนโค้ดด้านบนใหม่เพื่อให้ชัดเจนยิ่งขึ้น

var callback = function () {
  console.log("10 seconds later...");
};
setTimeout(callback, 10000);

การโทรกลับถูกใช้ทั่วทุกที่ในโหนดเนื่องจากโหนดถูกสร้างขึ้นจากพื้นดินขึ้นไปเป็นแบบอะซิงโครนัสในทุกสิ่งที่ทำ แม้จะคุยกับระบบไฟล์. นั่นเป็นเหตุผลที่ Node API ภายในจำนวนมากยอมรับฟังก์ชันการเรียกกลับเป็นอาร์กิวเมนต์แทนที่จะส่งคืนข้อมูลที่คุณสามารถกำหนดให้กับตัวแปรได้ แต่จะเรียกใช้ฟังก์ชันเรียกกลับของคุณโดยส่งผ่านข้อมูลที่คุณต้องการเป็นอาร์กิวเมนต์ ตัวอย่างเช่นคุณสามารถใช้fsไลบรารีของ Node เพื่ออ่านไฟล์ fsโมดูล exposes สองฟังก์ชัน API ไม่ซ้ำกัน: และreadFilereadFileSync

readFileฟังก์ชั่นไม่ตรงกันในขณะที่ยังreadFileSyncไม่ชัด คุณจะเห็นว่าพวกเขาตั้งใจที่คุณใช้โทร async เมื่อใดก็ตามที่เป็นไปได้เนื่องจากพวกเขาเรียกว่าพวกเขาreadFileและreadFileSyncแทนและreadFile readFileAsyncนี่คือตัวอย่างของการใช้ทั้งสองฟังก์ชัน

ซิงโคร:

var data = fs.readFileSync('test.txt');
console.log(data);

รหัสดังกล่าวดำเนินการบล็อกด้ายจนเนื้อหาทั้งหมดของการอ่านในหน่วยความจำและเก็บไว้ในตัวแปรtest.txt dataในโหนดนี้ถือเป็นการปฏิบัติที่ไม่ดี มีหลายครั้งที่มันมีประโยชน์เช่นเมื่อเขียนสคริปต์เล็ก ๆ น้อย ๆ เพื่อทำสิ่งที่เรียบง่าย แต่น่าเบื่อและคุณไม่สนใจเกี่ยวกับการประหยัดเวลาทุก ๆ นาโนวินาทีเท่าที่จะทำได้

แบบอะซิงโครนัส (พร้อมการโทรกลับ):

var callback = function (err, data) {
  if (err) return console.error(err);
  console.log(data);
};
fs.readFile('test.txt', callback);

ก่อนอื่นเราสร้างฟังก์ชันเรียกกลับที่รับสองอาร์กิวเมนต์errและdata. ปัญหาอย่างหนึ่งของฟังก์ชันอะซิงโครนัสคือการดักจับข้อผิดพลาดทำได้ยากขึ้นดังนั้น API แบบเรียกกลับจำนวนมากจึงส่งข้อผิดพลาดเป็นอาร์กิวเมนต์แรกของฟังก์ชันเรียกกลับ แนวทางปฏิบัติที่ดีที่สุดคือตรวจสอบว่าerrมีค่าหรือไม่ก่อนที่จะดำเนินการอย่างอื่น หากเป็นเช่นนั้นให้หยุดการเรียกกลับและบันทึกข้อผิดพลาด

การโทรแบบซิงโครนัสมีข้อได้เปรียบเมื่อมีข้อยกเว้นเนื่องจากคุณสามารถจับได้ด้วยtry/catchบล็อก

try {
  var data = fs.readFileSync('test.txt');
  console.log(data);
} catch (err) {
  console.error(err);
}

ในฟังก์ชันอะซิงโครนัสจะไม่ทำงานในลักษณะนั้น การเรียก API จะส่งคืนทันทีดังนั้นจึงไม่มีสิ่งใดที่จะจับกับไฟล์try/catch. API แบบอะซิงโครนัสที่เหมาะสมซึ่งใช้การเรียกกลับจะตรวจจับข้อผิดพลาดของตนเองได้เสมอจากนั้นจึงส่งข้อผิดพลาดเหล่านั้นไปยังการเรียกกลับซึ่งคุณสามารถจัดการได้ตามที่เห็นสมควร

นอกเหนือจากการเรียกกลับแล้วยังมีอีกรูปแบบหนึ่งที่เป็นที่นิยมของ API ที่มักใช้เรียกว่าสัญญา หากคุณต้องการที่จะอ่านเกี่ยวกับพวกเขาแล้วคุณสามารถอ่านบล็อกโพสต์ทั้งหมดที่ผมเขียนอยู่บนพื้นฐานของคำตอบนี้ที่นี่


3
การส่งมอบแนวคิดที่ค่อนข้างซับซ้อน แต่กระชับ สำหรับผู้เริ่มต้น node.js อย่างฉัน ...
kmonsoor

3
+1 สำหรับการให้บริบทมากมาย ไม่เพียง แต่ฟังก์ชันเรียกกลับจะมีลักษณะอย่างไร แต่คืออะไรทำไมจึงใช้และเหตุใดจึงมีการใช้งานมาก เป็นประโยชน์สำหรับผู้เริ่มต้นจริงๆ
Azurespot

1
ที่ดี! นี่อาจเป็นโพสต์เองก็ได้!
Pablo Glez

1
มันเป็นและรวมถึงส่วนที่สองเกี่ยวกับคำสัญญา;)
Chev

1
นี่เป็นคำอธิบายที่ดีกว่าคำตอบที่ยอมรับ! ฉันชอบทุกคำตอบที่ได้รับการยอมรับใน SO จะเป็นเช่นนั้น - ไม่เพียง แต่เป็นโค้ดที่ช่วยแก้ปัญหาเท่านั้น แต่ยังรวมถึงเหตุผลและวิธีการแก้ปัญหาด้วย โดยทั่วไปคำตอบและ callbackhell นี้จะทำให้คุณมีความเข้าใจที่ชัดเจนว่าการโทรกลับคืออะไร
RusI

10

นี่คือตัวอย่างของการคัดลอกไฟล์ข้อความด้วยfs.readFileและfs.writeFile:

var fs = require('fs');

var copyFile = function(source, destination, next) {
  // we should read source file first
  fs.readFile(source, function(err, data) {
    if (err) return next(err); // error occurred
    // now we can write data to destination file
    fs.writeFile(destination, data, next);
  });
};

และนั่นคือตัวอย่างของการใช้copyFileฟังก์ชัน:

copyFile('foo.txt', 'bar.txt', function(err) {
  if (err) {
    // either fs.readFile or fs.writeFile returned an error
    console.log(err.stack || err);
  } else {
    console.log('Success!');
  }
});

รูปแบบโหนด js ทั่วไปแสดงว่าอาร์กิวเมนต์แรกของฟังก์ชันเรียกกลับเป็นข้อผิดพลาด คุณควรใช้รูปแบบนี้เนื่องจากโมดูลโฟลว์ควบคุมทั้งหมดพึ่งพามัน:

next(new Error('I cannot do it!')); // error

next(null, results); // no error occurred, return result

2
ต่อไปคืออะไร? ผลลัพธ์ตัวแปรคืออะไร = สิ่งที่ถูกเรียก?
The Nomadic Coder

3
@Semicolon นำตัวชี้สำหรับฉันและคนอื่น ๆ : stackoverflow.com/questions/5384526/javascript-node-js-next
kmonsoor

7

ลองใช้ตัวอย่างนี้ง่ายๆเท่าที่คุณสามารถอ่านได้เพียงคัดลอกบันทึก newfile.js ทำ node newfile เพื่อเรียกใช้แอปพลิเคชัน

function myNew(next){
    console.log("Im the one who initates callback");
    next("nope", "success");
}


myNew(function(err, res){
    console.log("I got back from callback",err, res);
});

3

เรากำลังสร้างฟังก์ชันง่ายๆเป็น

callBackFunction (data, function ( err, response ){
     console.log(response)
}) 

// callbackfunction 
function callBackFuntion (data, callback){
    //write your logic and return your result as
callback("",result) //if not error
callback(error, "") //if error
}

1
const fs = require('fs');

fs.stat('input.txt', function (err, stats) {
    if(err){
        console.log(err);
    } else {
        console.log(stats);
        console.log('Completed Reading File');
    }
});

'fs' เป็นโมดูลโหนดที่ช่วยให้คุณอ่านไฟล์ ฟังก์ชันเรียกกลับจะตรวจสอบให้แน่ใจว่าไฟล์ของคุณชื่อ 'input.txt' ถูกอ่านอย่างสมบูรณ์ก่อนที่จะดำเนินการ fs.stat () ฟังก์ชั่นรับข้อมูลไฟล์เช่นขนาดไฟล์วันที่สร้างและวันที่แก้ไข



0

A callbackคือฟังก์ชันที่ส่งผ่านเป็นพารามิเตอร์ไปยังHigher Order Function( wikipedia ) การใช้การโทรกลับอย่างง่าย ๆ คือ:

const func = callback => callback('Hello World!');

ในการเรียกใช้ฟังก์ชันให้ส่งฟังก์ชันอื่นเป็นอาร์กิวเมนต์ไปยังฟังก์ชันที่กำหนดไว้

func(string => console.log(string));

0

บล็อกโพสต์นี้มีการเขียนที่ดี:

https://codeburst.io/javascript-what-the-heck-is-a-callback-aba4da2deced

function doHomework(subject, callback) {
  alert(`Starting my ${subject} homework.`);
  callback();
}

function alertFinished(){
  alert('Finished my homework');
}

doHomework('math', alertFinished);

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.