ধারাবাহিকতা / কলব্যাকগুলি পঠনযোগ্য সহ আপনি কীভাবে কোড রাখবেন?


11

সংক্ষিপ্তসার: অ্যাসিঙ্ক্রোনাস কোড এবং কলব্যাক্স সত্ত্বেও আমার কোডটি পাঠযোগ্যযোগ্য রাখতে আমি অনুসরণ করতে পারি এমন কিছু সু-প্রতিষ্ঠিত সেরা অনুশীলনের নিদর্শন রয়েছে কি?


আমি একটি জাভাস্ক্রিপ্ট লাইব্রেরি ব্যবহার করছি যা প্রচুর পরিমাণে অ্যাসিঙ্ক্রোনালি করে এবং ভারী কলব্যাকগুলিতে নির্ভর করে। দেখে মনে হচ্ছে যে একটি সাধারণ "লোড এ, লোড বি, ..." পদ্ধতিটি এই প্যাটার্নটি ব্যবহার করে অনুসরণ করা বেশ জটিল এবং শক্ত হয়ে যায়।

আমাকে একটি (স্বীকৃত) উদাহরণ দিন। ধরা যাক যে আমি একটি রিমোট ওয়েব সার্ভার থেকে একগুচ্ছ চিত্রগুলি (অবিচ্ছিন্ন) লোড করতে চাই। সি # / অ্যাসিঙ্কে আমি এই জাতীয় কিছু লিখতাম:

disableStartButton();

foreach (myData in myRepository) {
    var result = await LoadImageAsync("http://my/server/GetImage?" + myData.Id);
    if (result.Success) {
        myData.Image = result.Data;
    } else {
        write("error loading Image " + myData.Id);
        return;
    }
}

write("success");
enableStartButton();

কোড লেআউটটি "ইভেন্টগুলির প্রবাহ" অনুসরণ করে: প্রথমে, স্টার্ট বোতামটি অক্ষম করা হয়, তারপরে চিত্রগুলি লোড করা হয় ( awaitইউআইটি প্রতিক্রিয়াশীল থাকে তা নিশ্চিত করে) এবং তারপরে আবার স্টার্ট বোতামটি সক্ষম করা হয়।

জাভাস্ক্রিপ্টে, কলব্যাকগুলি ব্যবহার করে, আমি এটি নিয়ে এসেছি:

disableStartButton();

var count = myRepository.length;

function loadImage(i) {
    if (i >= count) {
        write("success");
        enableStartButton();
        return;
    }

    myData = myRepository[i];
    LoadImageAsync("http://my/server/GetImage?" + myData.Id,
        function(success, data) { 
            if (success) {
                myData.Image = data;
            } else {
                write("error loading image " + myData.Id);
                return;
            }
            loadImage(i+1); 
        }
    );
}

loadImage(0);

আমি মনে করি যে ত্রুটিগুলি সুস্পষ্ট: আমাকে লুপটিকে একটি পুনরাবৃত্ত কলের মধ্যে পুনরায় কাজ করতে হয়েছিল, শেষ পর্যন্ত কার্যকর করা হবে বলে মনে করা কোডটি ফাংশনের মাঝখানে কোথাও রয়েছে, ডাউনলোড ( loadImage(0)) ডাউনলোড শুরু করার কোডটি খুব নীচে রয়েছে, এবং এটি পড়তে এবং অনুসরণ করা সাধারণত কঠিন। এটি কুৎসিত এবং আমি এটি পছন্দ করি না।

আমি নিশ্চিত যে আমি এই সমস্যার মুখোমুখি হওয়া প্রথম ব্যক্তি নই, সুতরাং আমার প্রশ্নটি: অ্যাসিঙ্ক্রোনাস কোড এবং কলব্যাক্স সত্ত্বেও আমার কোডটি পাঠযোগ্য রাখার জন্য আমি কি কিছু সু-প্রতিষ্ঠিত সেরা অনুশীলনের ধরণগুলি অনুসরণ করতে পারি?


আপনার "অ্যাসিঙ্ক" কলগুলি ক্রমান্বয়ে করতে হবে এমন কোনও কারণ আছে? এটি কি অন্য কোনও কোডের সরলিকৃত সংস্করণ?
ইজকাটা

@ ইজকাটা: কারণটি হ'ল আমি দূরবর্তী সার্ভারের সাথে সুন্দর হতে চেয়েছি (= একসাথে শত শত অনুরোধের সাথে এটি বোমা না)। এটি পাথর মধ্যে সেট প্রয়োজন হয় না। হ্যাঁ, এটি কোডের একটি সরল সংস্করণ, LoadImageAsyncআসলে Ext.Ajax.requestসেঞ্চা টাচের কল ।
হেইনজি

1
বেশিরভাগ ব্রাউজারগুলি আপনাকে যে কোনও উপায়ে সার্ভারকে হাতুড়ি দেওয়ার অনুমতি দেয় না - তারা কেবল অনুরোধগুলি সারি করে এবং পূর্বের কোনও একটি সম্পূর্ণ করার পরে পরবর্তীটি শুরু করে।
ইজকাটা


সৃষ্টিকর্তা! এখানে খারাপ পরামর্শ প্রচুর। কোনও পরিমাণ নকশার নিদর্শন আপনাকে সাহায্য করবে না। দেখব async.js , async.waterfallআপনার উত্তর।
সালমান ভন আব্বাস

উত্তর:


4

এটি অত্যন্ত সম্ভাবনা নয় যে আপনি প্লেইন জেএসের সাথে সি # 5 এর কলব্যাকগুলির সাথে কাজ করার ক্ষেত্রে একই স্তরের সংক্ষিপ্ততা এবং ভাববাদিতা অর্জন করতে পারেন। সংকলকটি আপনার জন্য সমস্ত বয়লারপ্লেট লেখার কাজ করে এবং জেএস রানটাইমগুলি এটি না করা পর্যন্ত আপনাকে এখানে এবং সেখানে একটি অনিয়মিত কলব্যাক পাস করতে হবে।

যাইহোক, যদি আপনি পারেন সবসময় রৈখিক কোডের সরলতা পর্যায়ে নেমে callbacks আনতে চাই - প্রায় নিক্ষেপ ফাংশন কুশ্রী হতে হবে তা নয়, একটি এর সমগ্র বিশ্বের কোড এই ধরনের কাজ, এবং তারা ছাড়া বিবেকী রাখা asyncএবং await

উদাহরণস্বরূপ, উচ্চ-অর্ডার ফাংশনগুলি ব্যবহার করুন (আমার জেএসটি কিছুটা মরিচা হতে পারে):

// generic - this is a library function
function iterateAsync(iterator, action, onSuccess, onFailure) {
var item = iterator();
if(item == null) { // exit condition
    onSuccess();
    return;
}
action(item,
    function (success) {
        if(success)
            iterateAsync(iterator, action, onSuccess, onFailure);
        else
            onFailure();
    });
}


// calling code
var currentImage = 0;
var imageCount = 42;

// you know your library function expects an iterator with no params, 
// and an async action with the current item and its continuation as params
iterateAsync(
// this is your iterator
function () {   
    if(currentImage >= imageCount)
        return null;
    return "http://my/server/GetImage?" + (currentImage++);
},

// this is your action - coincidentally, no adaptor for the correct signature is necessary
LoadImageAsync,

// these are your outs
function () { console.log("All OK."); },
function () { console.log("FAILED!"); }
);

2

আপনি কেন এইভাবে এটি করছেন তা ডিকোড করতে আমাকে কিছুটা সময় নিয়েছিল তবে আমি মনে করি এটি আপনি যা চান তার কাছাকাছি হতে পারে?

function loadImages() {
   var countRemainingToLoad = 0;
   var failures = 0;

   myRepository.each(function (myData) {
      countRemainingToLoad++;

      LoadImageAsync("http://my/server/GetImage?" + myData.Id,
        function(success, data) {
            if (success) {
                myData.Image = data;
            } else {
                write("error loading image " + myData.Id);
                failures++;
            }
            countRemainingToLoad--;
            if (countRemainingToLoad == 0 && failures == 0) {
                enableStartButton();
            }
        }
    );
}

disableStartButton();
loadImages();

এটি একইসাথে যতগুলি অ্যাজেএক্স অনুরোধ করতে পারে তা প্রথম বন্ধ করে দেয় এবং স্টার্ট বোতামটি সক্ষম করার আগে সেগুলি সমস্ত শেষ না হওয়া পর্যন্ত এটি অপেক্ষা করে। এটি ক্রমিক অপেক্ষা অপেক্ষা দ্রুততর হবে এবং আমি মনে করি এটি অনুসরণ করা আরও সহজ।

সম্পাদনা : নোট করুন যে এটি ধরে নিয়েছে যে আপনার .each()উপলব্ধ রয়েছে এবং এটি myRepositoryএকটি অ্যারে। আপনি তার জায়গায় এখানে কোন লুপ পুনরাবৃত্তিটি ব্যবহার করেন তা সাবধান হন, যদি এটি উপলব্ধ না হয় - এইটি কলব্যাকের জন্য ক্লোজার বৈশিষ্ট্যের সুবিধা গ্রহণ করে। আপনার কাছে যা আছে তা আমি নিশ্চিত নই, যদিও, যেহেতু LoadImageAsyncএকটি বিশেষ লাইব্রেরির অংশ বলে মনে হচ্ছে - গুগলে আমি কোনও ফলাফল দেখছি না।


+1, আমার কাছে .each()উপলব্ধ আছে এবং এখন আপনি এটি উল্লেখ করেছেন, ক্রমান্বয়ে লোডটি করা কঠোরভাবে প্রয়োজন হয় না। আমি অবশ্যই আপনার সমাধানটি চেষ্টা করে দেখব। (যদিও আমি ভিস্কির উত্তরটি গ্রহণ করব, যেহেতু এটি মূল, আরও সাধারণ প্রশ্নের কাছাকাছি))
হেইঞ্জি

@ হেইনজি এটি কতটা পৃথক তার সাথে একমত পোষণ করেছেন, তবে (আমার মনে হয়) বিভিন্ন ভাষা একই জিনিসকে পরিচালনা করার বিভিন্ন উপায় কীভাবে এটির একটি শালীন উদাহরণ। কোনও ভিন্ন ভাষায় অনুবাদ করার সময় যদি কিছু অস্বস্তি বোধ করে, তবে আলাদা দৃষ্টান্ত ব্যবহার করে এটি করার সহজ উপায় সম্ভবত।
ইজকাটা

1

অস্বীকৃতি: এই উত্তরটি আপনার সমস্যার নির্দিষ্টভাবে উত্তর দেয় না, এটি প্রশ্নের জেনারিক উত্তর: "অ্যাসিঙ্ক্রোনাস কোড এবং কলব্যাক্স সত্ত্বেও আমার কোডটি পাঠযোগ্যযোগ্য রাখতে আমি কি কিছু সুপ্রতিষ্ঠিত সেরা অনুশীলনের ধরণ অনুসরণ করতে পারি?"

আমি যা জানি, এটি পরিচালনা করার জন্য কোনও "সুপ্রতিষ্ঠিত" ধরণ নেই। তবে, আমি নেস্টেড কলব্যাকস দুঃস্বপ্ন এড়াতে দুটি ধরণের পদ্ধতি দেখেছি।

1 / বেনামে কলব্যাকের পরিবর্তে নামযুক্ত ফাংশন ব্যবহার করা

    function start() {
        mongo.findById( id, handleDatas );
    }

    function handleDatas( datas ) {
        // Handle the datas returned.
    }

এইভাবে, আপনি অন্য ফাংশনে বেনাম ফাংশনের যুক্তি প্রেরণ করে বাসা বাঁধবেন avoid

2 / একটি ফ্লো ম্যানেজমেন্ট লাইব্রেরি ব্যবহার। আমি পদক্ষেপটি ব্যবহার করতে পছন্দ করি তবে এটি কেবল পছন্দের বিষয়। এটি একমাত্র লিঙ্কডইন ব্যবহার করে uses

    Step( {
        function start() {
            // the "this" magically sends to the next function.
            mongo.findById( this );
        },

        function handleDatas( el ) {
            // Handle the datas.
            // Another way to use it is by returning a value,
            // the value will be sent to the next function.
            // However, this is specific to Step, so look at
            // the documentation of the library you choose.
            return value;
        },

        function nextFunction( value ) {
            // Use the returned value from the preceding function
        }
    } );

যখন আমি প্রচুর নেস্টেড কলব্যাক ব্যবহার করি তখন আমি একটি ফ্লো ম্যানেজমেন্ট লাইব্রেরি ব্যবহার করি কারণ যখন প্রচুর কোড ব্যবহার করা হয় তখন এটি অনেক বেশি পাঠযোগ্য।


0

সোজা কথায়, জাভাস্ক্রিপ্টের সিনট্যাকটিক চিনি নেই await
তবে "শেষ" অংশটি ফাংশনের নীচে সরানো সহজ; এবং তাত্ক্ষণিকভাবে একটি অনামী কার্য সম্পাদন করে, আমরা এর কোনও রেফারেন্স ঘোষণা এড়াতে পারি।

disableStartButton();

(function(i, count) {
    var loadImage = arguments.callee;
    myData = myRepository[i];

    LoadImageAsync("http://my/server/GetImage?" + myData.Id,
        function(success, data) { 
            if (!success) {
                write("error loading image " + myData.Id);

            } else {
                myData.Image = data;
                if (i < count) {
                    loadImage(i + 1, count);

                } else {
                    write("success");
                    enableStartButton();
                    return;

                }

            }

        }
    );
})(0, myRepository.length);

আপনি কার্যটির সাফল্য-কলব্যাক হিসাবে "শেষ" অংশটিও পাস করতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.