سؤال

في Nodejs، لا توجد عمليات إدخال/إخراج محظورة فعليًا.هذا يعني أن جميع أكواد Nodejs IO تقريبًا تتضمن العديد من عمليات الاسترجاعات.ينطبق هذا على القراءة والكتابة من/إلى قواعد البيانات والملفات والعمليات وما إلى ذلك.والمثال النموذجي على ذلك هو ما يلي:

var useFile = function(filename,callback){
    posix.stat(filename).addCallback(function (stats) {
        posix.open(filename, process.O_RDONLY, 0666).addCallback(function (fd) {
            posix.read(fd, stats.size, 0).addCallback(function(contents){
                callback(contents);
            });
        });
    });
};

...

useFile("test.data",function(data){
    // use data..
});

أتوقع كتابة التعليمات البرمجية التي من شأنها أن تجعل كثير عمليات الإدخال والإخراج، لذلك أتوقع أن أكتب كثير الاسترجاعات.أنا مرتاح جدًا لاستخدام عمليات الاسترجاعات، لكني قلق بشأن كل التكرار.هل أنا في خطر الوقوع في الكثير من التكرار والنفخ في كومة في مكان ما؟إذا قمت بإجراء آلاف عمليات الكتابة الفردية إلى مخزن القيمة الرئيسية الخاص بي مع الآلاف من عمليات الاسترجاعات، فهل سيتعطل برنامجي في النهاية؟

هل أسيء فهم التأثير أم أقلل منه؟إذا لم يكن الأمر كذلك، فهل هناك طريقة للتغلب على هذا مع الاستمرار في استخدام نمط ترميز رد الاتصال الخاص بـ Nodejs؟

هل كانت مفيدة؟

المحلول

لا يستخدم أي من التعليمات البرمجية التي تظهرها العودية.عندما تتصل useFile يدعو posix.stat(), ، والذي يعود، و useFile ينتهي لأنه تم تشغيله حتى الاكتمال.في وقت لاحق، عند الاتصال بـ posix.stat() أكملت داخل النظام الأساسي وعندما تتوفر النتائج، سيتم تنفيذ وظيفة رد الاتصال التي أضفتها لذلك.هذا يدعو posix.open(), ، ثم ينتهي بعد أن تم تشغيله حتى الاكتمال.بمجرد فتح الملف بنجاح، ستتم وظيفة رد الاتصال لـ الذي - التي سيتم تنفيذ، الدعوة posix.read(), ، وسيتم إنهاؤه بعد ذلك لأنه قد تم أيضًا تشغيله حتى الاكتمال.أخيرًا، عندما تتوفر نتائج القراءة، سيتم تنفيذ الوظيفة الأعمق.

النقطة المهمة هي أن كل وظيفة تعمل حتى الاكتمال، كما يتم استدعاء posix.*() الوظائف غير محظورة:أي أنهم يعودون على الفور، بعد أن تسببوا في بدء بعض السحر في النظام الأساسي.لذلك تنتهي كل وظيفة من وظائفك، وبعد ذلك سيؤدي حدث ما إلى تنفيذ الوظيفة التالية؛ولكن ليس هناك أي تكرار في أي وقت.

يمكن للبنية المتداخلة للكود أن تعطي انطباعًا بأن العناصر الموجودة بالداخل يجب أن تنتهي قبل أن تصل العناصر الموجودة بالخارج إلى نقطة النهاية الخاصة بها.ولكن في هذا النمط من البرمجة غير المتزامنة التي تعتمد على الأحداث، يكون من المنطقي رؤية التداخل من حيث أعمق => يحدث في وقت لاحق من.

يحرر:حاول إضافة بعض بيانات التسجيل مباشرة قبل نهاية كل وظيفة متداخلة؛سيساعد هذا في توضيح أن الترتيب الذي يكملونه هو من الخارج إلى الداخل.

نصائح أخرى

نفس المثال، مع إضافة مخرجات التصحيح (انظر أدناه للحصول على المخرجات):

usefile.js:

var sys = require("sys"),
  posix = require("posix");

var useFile = function(filename,callback){
    posix.stat(filename).addCallback(function (stats) {
        posix.open(filename, process.O_RDONLY, 0666).addCallback(function (fd) {
            posix.read(fd, stats.size, 0).addCallback(function(contents){
                callback(contents);
                sys.debug("useFile callback returned");
            });
            sys.debug("read returned");
        });
        sys.debug("open returned");
    });
    sys.debug("stat returned");
};

useFile("usefile.js",function(){});

انتاج:

DEBUG: stat returned
DEBUG: open returned
DEBUG: read returned
DEBUG: useFile callback returned

يمكنك المحاولة

http://github.com/creationix/do

أو لفة بنفسك كما فعلت.لا تهتم بتجاهل معالجة الأخطاء في الوقت الحالي (فقط تجاهل ذلك) ;)

var sys = require('sys');

var Simplifier = exports.Simplifier = function() {}

Simplifier.prototype.execute = function(context, functions, finalFunction) {
  this.functions = functions;
  this.results = {};
  this.finalFunction = finalFunction;
  this.totalNumberOfCallbacks = 0
  this.context = context;
  var self = this;

  functions.forEach(function(f) {
    f(function() {
      self.totalNumberOfCallbacks = self.totalNumberOfCallbacks + 1;
      self.results[f] = Array.prototype.slice.call(arguments, 0);     
      if(self.totalNumberOfCallbacks >= self.functions.length) {
        // Order the results by the calling order of the functions
        var finalResults = [];
        self.functions.forEach(function(f) {
          finalResults.push(self.results[f][0]);
        })
        // Call the final function passing back all the collected results in the right order 
        finalFunction.apply(self.context, finalResults);
      }
    });
  });
}

ومثال بسيط استخدامه

// Execute 
new simplifier.Simplifier().execute(
  // Context of execution
  self,  
  // Array of processes to execute before doing final handling
  [function(callback) {
      db.collection('githubusers', function(err, collection) {
        collection.find({}, {limit:30}, function(err, cursor) {
          cursor.toArray(function(err, users) { callback(users); })
        });
      });      
    },

    function(callback) {
      db.collection('githubprojects', function(err, collection) {
        collection.find({}, {limit:45, sort:[['watchers', -1]]}, function(err, cursor) {
          cursor.toArray(function(err, projects) { callback(projects); })
        });
      });              
    }
  ],  
  // Handle the final result
  function(users, projects) {
    // Do something when ready
  }
);

الأشياء الخاصة بك على ما يرام.أقوم بإجراء مكالمات متكررة في Express لمتابعة عمليات إعادة توجيه HTTP، ولكن ما تفعله هو "اجتياز" وليس العودية

ألقِ نظرة أيضًا على "الخطوة" (http://github.com/creationix/step) أو "flow-js" على جيثب.يتيح لك ذلك كتابة تدفقات رد الاتصال بأسلوب أكثر طبيعية.سيوضح هذا أيضًا أنه لا يوجد تكرار يحدث.

كما هو الحال مع أي JavaScript، من الممكن إجراء مكالمات متكررة باستخدام Node.js.إذا واجهت مشاكل في عمق العودية (كما يشير NickFitz، لا يبدو أنك في خطر من ذلك)، يمكنك غالبًا إعادة كتابة التعليمات البرمجية الخاصة بك لاستخدام مؤقت الفاصل الزمني بدلاً من ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top