झंडा = सत्य होने तक प्रतीक्षा करें


94

मेरे पास इस तरह जावास्क्रिप्ट फ़ंक्शन है:

function myFunction(number) {

    var x=number;
    ...
    ... more initializations
    //here need to wait until flag==true
    while(flag==false)
    {}

    ...
    ... do something

}

समस्या यह है कि जावास्क्रिप्ट कुछ देर में अटक जाता है और मेरे कार्यक्रम को अटक जाता है। इसलिए मेरा सवाल यह है कि मैं समारोह के बीच में तब तक इंतजार कर सकता हूं जब तक झंडा "व्यस्त-प्रतीक्षा" के बिना सच न हो जाए?


3
अपने initializations के लिए वादा पैटर्न का उपयोग करें - काफी कुछ पुस्तकालयों में पाया जा सकता है की तरह है jQuery.Deferred, Q, async, ...
Sirko

वास्तव में इसका उपयोग कैसे करें और कैसे करें?
इले ज़ीडमैन

1
विभिन्न पुस्तकालयों के वादे के कार्यान्वयन का वर्णन करने के आसपास बहुत सारे ट्यूटोरियल हैं, जैसे। jQuery.Deferred या क्यू । Btw, आपकी अंतर्निहित समस्या इस प्रश्न के समान है ।
सिरको

3
2018 में इसे पढ़ने वाले किसी व्यक्ति के लिए, प्रॉमिस को ओपेरा मिनी और IE11 के अलावा सभी ब्राउज़रों द्वारा समर्थित किया गया है।
डैनियल रीना

मुख्य समस्या यह है कि इवेंट-डिवेन सिंगल-थ्रेडेड जेएस में वास्तव में अवरुद्ध (नींद) प्रतीक्षा करना असंभव है। आप केवल प्रतीक्षा हैंडलर बना सकते हैं। और देखें: stackoverflow.com/questions/41842147/…
SalientBrain 13

जवाबों:


73

क्योंकि एक ब्राउज़र में जावास्क्रिप्ट एकल थ्रेडेड है (वेबवर्कर्स को छोड़कर जो यहां शामिल नहीं हैं) और जावास्क्रिप्ट निष्पादन का एक धागा दूसरे को चलाने से पहले पूरा करने के लिए चलता है, आपका बयान:

while(flag==false) {}

बस हमेशा के लिए चलेगा (या जब तक कि ब्राउज़र एक गैर-उत्तरदायी जावास्क्रिप्ट लूप के बारे में शिकायत नहीं करता है), पृष्ठ लटका हुआ दिखाई देगा और किसी अन्य जावास्क्रिप्ट को कभी भी चलाने का मौका नहीं मिलेगा, इस प्रकार ध्वज का मान कभी नहीं बदला जा सकता है।

थोड़ी और व्याख्या के लिए, जावास्क्रिप्ट एक घटना संचालित भाषा है । इसका मतलब है कि यह जावास्क्रिप्ट का एक टुकड़ा चलाता है जब तक कि यह इंटरप्रेटर पर वापस नियंत्रण नहीं करता है। फिर, केवल जब यह दुभाषिया पर वापस लौटता है, तो जावास्क्रिप्ट को घटना कतार से अगली घटना मिलती है और इसे चलाता है।

सभी चीजें जैसे टाइमर और नेटवर्क ईवेंट इवेंट क्यू के माध्यम से चलते हैं। इसलिए, जब एक टाइमर फायर होता है या नेटवर्क अनुरोध आता है, तो यह वर्तमान में चल रहे जावास्क्रिप्ट को "बाधित" नहीं करता है। इसके बजाय, एक घटना जावास्क्रिप्ट इवेंट कतार में डाल दी जाती है और फिर, जब वर्तमान में चल रही जावास्क्रिप्ट खत्म हो जाती है, तो अगली घटना को इवेंट कतार से खींच लिया जाता है और इसे चलाने की बारी आती है।

इसलिए, जब आप एक अनंत लूप करते हैं जैसे कि while(flag==false) {}, वर्तमान में चल रहा जावास्क्रिप्ट कभी खत्म नहीं होता है और इस तरह अगली घटना कभी भी कतार से नहीं खींची जाती है और इस प्रकार flagकभी भी मूल्य नहीं बदला जाता है। वे यहाँ कुंजी यह है कि जावास्क्रिप्ट संचालित बाधित नहीं है । जब टाइमर फायर करता है, तो यह वर्तमान में चल रहे जावास्क्रिप्ट को बाधित नहीं करता है, कुछ अन्य जावास्क्रिप्ट को चलाएं और फिर वर्तमान में चल रहे जावास्क्रिप्ट को जारी रखें। यह सिर्फ घटना कतार में खड़ा हो जाता है जब तक कि वर्तमान में चल रहे जावास्क्रिप्ट को चलाने के लिए अपनी बारी लाने के लिए इंतजार नहीं किया जाता है।


आपको क्या करने की आवश्यकता है, इस पर पुनर्विचार करें कि आपका कोड कैसे काम करता है और flagमान बदलने पर जो भी कोड आप चलाना चाहते हैं उसे ट्रिगर करने का एक अलग तरीका खोजें । जावास्क्रिप्ट को एक इवेंट-संचालित भाषा के रूप में डिज़ाइन किया गया है। तो, आपको क्या करने की ज़रूरत है, यह पता लगाने के लिए कि आप किन घटनाओं में रुचि दर्ज कर सकते हैं ताकि आप या तो उस घटना को सुन सकें जो झंडा बदलने का कारण बन सकती है और आप उस घटना पर ध्वज की जांच कर सकते हैं या आप अपनी खुद की घटना को ट्रिगर कर सकते हैं जो भी कोड ध्वज को बदल सकता है या आप कॉलबैक फ़ंक्शन को कार्यान्वित कर सकते हैं जो भी कोड बदलता है वह ध्वज आपके कॉलबैक को कॉल कर सकता है जब भी ध्वज मूल्य को बदलने के लिए ज़िम्मेदार कोड का टुकड़ा इसे बदल देगा true, तो यह कॉलबैक फ़ंक्शन को कॉल करता है और इस प्रकार आपका कोड जब ध्वज सेट हो जाता है तो चलना चाहता हैtrueसही समय पर चलने के लिए मिलेगा। यह ध्वज मूल्य को लगातार जांचने के लिए किसी प्रकार के टाइमर का उपयोग करने की कोशिश करने की तुलना में बहुत अधिक कुशल है।

function codeThatMightChangeFlag(callback) {
    // do a bunch of stuff
    if (condition happens to change flag value) {
        // call the callback to notify other code
        callback();
    }
}

98

जावास्क्रिप्ट सिंगल थ्रेडेड है, इसलिए पेज ब्लॉकिंग बिहेवियर है। आप दूसरों द्वारा सुझाए गए आस्थगित / वादा दृष्टिकोण का उपयोग कर सकते हैं, लेकिन सबसे बुनियादी तरीका उपयोग करना होगा window.setTimeout। उदाहरण के लिए

function checkFlag() {
    if(flag == false) {
       window.setTimeout(checkFlag, 100); /* this checks the flag every 100 milliseconds*/
    } else {
      /* do something*/
    }
}
checkFlag();

यहाँ आगे स्पष्टीकरण के साथ एक अच्छा ट्यूटोरियल है: ट्यूटोरियल

संपादित करें

जैसा कि अन्य ने बताया, कॉलबैक का उपयोग करने के लिए अपने कोड को फिर से संरचना करने का सबसे अच्छा तरीका होगा। हालांकि, इस जवाब से आपको अंदाजा हो सकता है कि आप किस तरह से एक अतुल्यकालिक व्यवहार को 'अनुकरण' कर सकते हैं window.setTimeout


1
एक ओर जहां मैं वास्तव में इस जवाब को पसंद करता हूं क्योंकि यह वास्तव में एक जेएस 'प्रतीक्षा' है यदि आप एक मूल्य वापस करना चाहते हैं तो यह इतना उपयोगी नहीं है। यदि आप एक मूल्य वापस नहीं करते हैं तो मुझे यकीन नहीं है कि पैटर्न के लिए एक वास्तविक दुनिया usecase है?
मार्टिन मेसेर

आप निश्चित रूप से एक वादा वापस कर सकते हैं और उस तरह से फ़ंक्शन को लागू कर सकते हैं। हालाँकि, आम तौर पर आपको किसी तीसरे पक्ष के पुस्तकालय की आवश्यकता होती है जो वादे या पॉलीफ़िल लागू करता है, जब तक कि आप ECMA-262 का उपयोग नहीं कर रहे हैं। एक वादा वापस करने के बिना, कॉल करने वाले को संकेत देने के लिए कॉलबैक तंत्र का उपयोग करने का सबसे अच्छा तरीका है कि एक परिणाम उपलब्ध हो।
किरण

यदि आवश्यक हो तो आप पैरामीटर भी पास कर सकते हैं: stackoverflow.com/questions/1190642/…
SharpC

1
यह इतना बड़ा जवाब है। मैं कई तकनीकी मंचों के माध्यम से खुदाई करने के बाद लगभग छोड़ रहा था। मुझे लगता है कि यह मेरे लिए पूरी तरह से काम करता है क्योंकि मैं एक मूल्य वापस कर रहा था। यह इंटरनेट एक्सप्लोरर पर भी काम करता है। एक गुच्छा का धन्यवाद।
जोसफ

18

वादा , async \ प्रतीक्षा और EventEmitter का उपयोग कर समाधान , जो किसी भी प्रकार के लूप के बिना ध्वज परिवर्तन पर तत्काल प्रतिक्रिया करने की अनुमति देता है

const EventEmitter = require('events');

const bus = new EventEmitter();
let lock = false;

async function lockable() {
    if (lock) await new Promise(resolve => bus.once('unlocked', resolve));
    ....
    lock = true;
    ...some logic....
    lock = false;
    bus.emit('unlocked');
}

EventEmitterनोड में बनाया गया है। ब्राउज़र में आपको इसे अपने आप से शामिल करना होगा, उदाहरण के लिए इस पैकेज का उपयोग करना: https://www.npmjs.com/package/eemem3


17

ES6 Async / Await के साथ,

let meaningOfLife = false;
async function waitForMeaningOfLife(){
   while (true){
        if (meaningOfLife) { console.log(42); return };
        await null; // prevents app from hanging
   }
}
waitForMeaningOfLife();
setTimeout(()=>meaningOfLife=true,420)

1
लोगों को यह कैसे याद आया
Aviad

16
function waitFor(condition, callback) {
    if(!condition()) {
        console.log('waiting');
        window.setTimeout(waitFor.bind(null, condition, callback), 100); /* this checks the flag every 100 milliseconds*/
    } else {
        console.log('done');
        callback();
    }
}

उपयोग:

waitFor(() => window.waitForMe, () => console.log('got you'))

11

एक्मा स्क्रिप्ट 2017 के साथ आप एस्किंट-वेट का उपयोग कर सकते हैं और साथ में ऐसा करने के लिए और प्रोग्राम को क्रैश या लॉक नहीं करेंगे यहां तक ​​कि यह कभी भी सच नहीं है

//First define some delay function which is called from async function
function __delay__(timer) {
    return new Promise(resolve => {
        timer = timer || 2000;
        setTimeout(function () {
            resolve();
        }, timer);
    });
};

//Then Declare Some Variable Global or In Scope
//Depends on you
var flag = false;

//And define what ever you want with async fuction
async function some() {
    while (!flag)
        await __delay__(1000);

    //...code here because when Variable = true this function will
};


8

वादा का उपयोग कर आधुनिक समाधान

myFunction() मूल प्रश्न में निम्नानुसार संशोधन किया जा सकता है

async function myFunction(number) {

    var x=number;
    ...
    ... more initializations

    await until(_ => flag == true);

    ...
    ... do something

}

until()यह उपयोगिता समारोह कहां है

function until(conditionFunction) {

  const poll = resolve => {
    if(conditionFunction()) resolve();
    else setTimeout(_ => poll(resolve), 400);
  }

  return new Promise(poll);
}

Async / प्रतीक्षा और तीर फ़ंक्शन के कुछ संदर्भ एक समान पोस्ट में हैं: https://stackoverflow.com/a/52652681/2020794


4

प्रत्येक वस्तु पर ($ .each) ऑब्जेक्ट्स को पुनरावृत्त करने और एक लॉन्गिश-रनिंग ऑपरेशन (नेस्टेड अजाक्स सिंक कॉल युक्त) निष्पादित करने के लिए:

मैंने पहले एक रिवाज तय किया done=false प्रत्येक पर प्रॉपर्टी ।

फिर, एक पुनरावर्ती फ़ंक्शन में, प्रत्येक सेट करें done=trueऔर उपयोग करना जारी रखें setTimeout। (यह एक ऑपरेशन है मतलब अन्य सभी यूआई को रोकने के लिए, एक प्रगति बार दिखाने के लिए और इसलिए मैं अपने आप को सिंक कॉल के लिए माफ कर दिया सभी अन्य उपयोग को अवरुद्ध।)

function start()
{
    GlobalProducts = getproductsfromsomewhere();
    $.each(GlobalProducts, function(index, product) {
         product["done"] = false;
    });

    DoProducts();
}
function DoProducts()
{
    var doneProducts = Enumerable.From(GlobalProducts).Where("$.done == true").ToArray(); //linqjs

    //update progress bar here

    var nextProduct = Enumerable.From(GlobalProducts).Where("$.done == false").First();

        if (nextProduct) {
            nextProduct.done = true;
            Me.UploadProduct(nextProduct.id); //does the long-running work

            setTimeout(Me.UpdateProducts, 500)
        }
}

1

लाइटबर्ड के उत्तर के समान, मैं निम्नलिखित दृष्टिकोण का उपयोग करता हूं

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function until(fn) {
    while (!fn()) {
        await sleep(0)
    }
}

async function myFunction(number) {
    let x = number
    ...
    ... more initialization

    await until(() => flag == true)

    ...
    ... do something
}

1

मैंने @Kiran दृष्टिकोण का पालन करने की कोशिश की:

checkFlag: function() {
  var currentObject = this; 
  if(flag == false) {
      setTimeout(currentObject.checkFlag, 100); 
   } else {
     /* do something*/
   }
}

(फ्रेमवर्क कि मैं इस तरह से कार्यों को परिभाषित करने के लिए मुझे मजबूर कर रहा हूं)। लेकिन सफलता के बिना क्योंकि जब निष्पादन दूसरी बार checkFlag फ़ंक्शन के अंदर आता है, thisतो यह मेरी वस्तु नहीं है Window। इसलिए, मैं नीचे दिए गए कोड के साथ समाप्त हुआ

checkFlag: function() {
    var worker = setInterval (function(){
         if(flag == true){             
             /* do something*/
              clearInterval (worker);
         } 
    },100);
 }

1

EventTarget एपीआई के साथ गैर अवरुद्ध जावास्क्रिप्ट का उपयोग करना

मेरे उदाहरण में, मुझे इसे उपयोग करने से पहले कॉलबैक के लिए प्रतीक्षा करने की आवश्यकता है। मुझे कोई पता नहीं है कि यह कॉलबैक कब सेट किया गया है। इसे निष्पादित करने की आवश्यकता के बाद यह पहले हो सकता है। और मुझे इसे कई बार कॉल करने की आवश्यकता हो सकती है (सब कुछ async)

// bus to pass event
const bus = new EventTarget();

// it's magic
const waitForCallback = new Promise((resolve, reject) => {
    bus.addEventListener("initialized", (event) => {
        resolve(event.detail);
    });
});



// LET'S TEST IT !


// launch before callback has been set
waitForCallback.then((callback) => {
    console.log(callback("world"));
});


// async init
setTimeout(() => {
    const callback = (param) => { return `hello ${param.toString()}`; }
    bus.dispatchEvent(new CustomEvent("initialized", {detail: callback}));
}, 500);


// launch after callback has been set
setTimeout(() => {
    waitForCallback.then((callback) => {
        console.log(callback("my little pony"));
    });
}, 1000);


1

एक नोड पैकेज का delayउपयोग करने के लिए बहुत आसान है

const delay = require('delay');

(async () => {
    bar();

    await delay(100);

    // Executed 100 milliseconds later
    baz();
})();

1

मैंने यहां कॉलबैक समाधानों की तर्ज पर एक दृष्टिकोण लिया, लेकिन इसे थोड़ा और सामान्य बनाने की कोशिश की। विचार यह है कि आप उन कार्यों को जोड़ते हैं जिन्हें आपको कतार में कुछ परिवर्तन करने के बाद निष्पादित करने की आवश्यकता होती है। जब बात होती है, तो आप कतार से गुजरते हैं, फ़ंक्शन को कॉल करते हैं और कतार को खाली करते हैं।

फ़ंक्शन को कतार में जोड़ें:

let _queue = [];

const _addToQueue = (funcToQ) => {
    _queue.push(funcToQ);
}

निष्पादित करें और कतार को फ्लश करें:

const _runQueue = () => {
    if (!_queue || !_queue.length) {
        return;
    }

    _queue.forEach(queuedFunc => {
        queuedFunc();
    });

    _queue = [];
}

और जब आप _addToQueue का आह्वान करेंगे तो आप कॉलबैक को लपेटना चाहेंगे:

_addToQueue(() => methodYouWantToCallLater(<pass any args here like you normally would>));

जब आप शर्त पूरी कर लें, तो कॉल करें _runQueue()

यह मेरे लिए उपयोगी था क्योंकि मेरे पास कई चीजें थीं जो एक ही स्थिति पर प्रतीक्षा करने की आवश्यकता थी। और यह उस स्थिति का पता लगाने से रोकता है जो उस स्थिति के हिट होने पर निष्पादित होने की आवश्यकता है।


0

//function a(callback){
setTimeout(function() {
  console.log('Hi I am order 1');
}, 3000);
 // callback();
//}

//function b(callback){
setTimeout(function() {
  console.log('Hi I am order 2');
}, 2000);
//   callback();
//}



//function c(callback){
setTimeout(function() {
  console.log('Hi I am order 3');
}, 1000);
//   callback();

//}

 
/*function d(callback){
  a(function(){
    b(function(){
      
      c(callback);
      
    });
    
  });
  
  
}
d();*/


async function funa(){
  
  var pr1=new Promise((res,rej)=>{
    
   setTimeout(()=>res("Hi4 I am order 1"),3000)
        
  })
  
  
   var pr2=new Promise((res,rej)=>{
    
   setTimeout(()=>res("Hi4 I am order 2"),2000)
        
  })
   
    var pr3=new Promise((res,rej)=>{
    
   setTimeout(()=>res("Hi4 I am order 3"),1000)
        
  })

              
  var res1 = await pr1;
  var res2 = await pr2;
  var res3 = await pr3;
  console.log(res1,res2,res3);
  console.log(res1);
   console.log(res2);
   console.log(res3);

}   
    funa();
              


async function f1(){
  
  await new Promise(r=>setTimeout(r,3000))
    .then(()=>console.log('Hi3 I am order 1'))
    return 1;                        

}

async function f2(){
  
  await new Promise(r=>setTimeout(r,2000))
    .then(()=>console.log('Hi3 I am order 2'))
         return 2;                   

}

async function f3(){
  
  await new Promise(r=>setTimeout(r,1000))
    .then(()=>console.log('Hi3 I am order 3'))
        return 3;                    

}

async function finaloutput2(arr){
  
  return await Promise.all([f3(),f2(),f1()]);
}

//f1().then(f2().then(f3()));
//f3().then(f2().then(f1()));
  
//finaloutput2();

//var pr1=new Promise(f3)







async function f(){
  console.log("makesure");
  var pr=new Promise((res,rej)=>{
  setTimeout(function() {
  console.log('Hi2 I am order 1');
}, 3000);
  });
    
  
  var result=await pr;
  console.log(result);
}

 // f(); 

async function g(){
  console.log("makesure");
  var pr=new Promise((res,rej)=>{
  setTimeout(function() {
  console.log('Hi2 I am order 2');
}, 2000);
  });
    
  
  var result=await pr;
  console.log(result);
}
  
// g(); 

async function h(){
  console.log("makesure");
  var pr=new Promise((res,rej)=>{
  setTimeout(function() {
  console.log('Hi2 I am order 3');
}, 1000);
  });
    
  
  var result=await pr;
  console.log(result);
}

async function finaloutput(arr){
  
  return await Promise.all([f(),g(),h()]);
}
  
//finaloutput();

 //h(); 
  
  
  
  
  
  


0

मेरे उदाहरण में, मैं हर पल एक नया काउंटर मान दर्ज करता हूं:

var promises_arr = [];
var new_cntr_val = 0;

// fill array with promises
for (let seconds = 1; seconds < 10; seconds++) {
    new_cntr_val = new_cntr_val + 5;    // count to 50
    promises_arr.push(new Promise(function (resolve, reject) {
        // create two timeouts: one to work and one to resolve the promise
        setTimeout(function(cntr) {
            console.log(cntr);
        }, seconds * 1000, new_cntr_val);    // feed setTimeout the counter parameter
        setTimeout(resolve, seconds * 1000);
    }));
}

// wait for promises to finish
Promise.all(promises_arr).then(function (values) {
    console.log("all promises have returned");
});


0

यदि आपको उपयोग करने की अनुमति है: async/awaitअपने कोड पर, आप इसे आज़मा सकते हैं:

const waitFor = async (condFunc: () => boolean) => {
  return new Promise((resolve) => {
    if (condFunc()) {
      resolve();
    }
    else {
      setTimeout(async () => {
        await waitFor(condFunc);
        resolve();
      }, 100);
    }
  });
};

const myFunc = async () => {
  await waitFor(() => (window as any).goahead === true);
  console.log('hello world');
};

myFunc();

यहाँ डेमो: https://stackblitz.com/edit/typescript-bgtnhj?file=index.ts

कंसोल पर, बस कॉपी / पेस्ट करें goahead = true:।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.