मैं जावास्क्रिप्ट प्रॉम्प्ट की स्थिति को कैसे सिंक्रनाइज़ कर सकता हूं?


149

मेरे पास एक शुद्ध जावास्क्रिप्ट वादा है (अंतर्निहित कार्यान्वयन या पॉली-फिल):

var promise = new Promise(function (resolve, reject) { /* ... */ });

से विनिर्देश , एक वादा में से एक हो सकते हैं:

  • 'बसे' और 'हल'
  • 'बसे' और 'अस्वीकृत'
  • 'लंबित'

मेरे पास एक उपयोग का मामला है जहां मैं वादा करने के लिए तुल्यकालिक रूप से पूछताछ करना चाहता हूं और निर्धारित करता हूं:

  • वादा किया गया है?

  • यदि हां, तो क्या वादा हल हो गया है?

मुझे पता है कि मैं #then()वादा परिवर्तन की स्थिति के बाद अतुल्यकालिक प्रदर्शन के लिए काम करने के लिए अनुसूची का उपयोग कर सकता हूं । मैं यह नहीं पूछ रहा हूं कि यह कैसे करना है।

यह प्रश्न विशेष रूप से एक वचन की स्थिति के समकालिक पूछताछ के बारे में है । इसे कैसे प्राप्त किया जा सकता है?


6
वादे पर एक संपत्ति सेट करें जिसे बाहर से देखा जा सकता है, और फिर () संपत्ति को बदलने के लिए उपयोग करें।
डंडविस

@jokeyrhyme fwiw, v8 स्रोत code.google.com/p/v8/source/browse/branches/bleeding_edge/src/... देख var promiseStatus = NEW_PRIVATE("Promise#status");, PromiseSetपर समारोहSET_PRIVATE(promise, promiseStatus, status);
guest271314

यहाँ हम चलते हैं: esdiscuss.org/topic/…
jokeyrhyme

यह अजीब लगता है कि अगर आप एक कांस्टेंट a = Promise.resolve ('बाज') करते हैं; console.log (क); और Chrome कंसोल में देखें, आप Promise {[[PromiseStatus]]: "हल", [[PromiseValue]]: "baz"} प्रोटो: Promise [[PromiseStatus]]: "हल [[PromiseValue]]:" baz देखें "और लोगों का दावा है कि यह नहीं किया जा सकता है। क्रोम कैसे कर रहा है? (एंगुलर plnkr.co/edit/IPIWgLJKQStI5ubXmcsF
JGFMK

नोड v11.12.0 कंसोल का उपयोग करके। वादा स्थिति दिखाएगा। ईजी console.log(Promise.new((resolve, reject) => {})=>Promise { <pending> }
पुहलज

जवाबों:


77

देशी जावास्क्रिप्ट वादों के लिए ऐसा कोई समकालिक निरीक्षण एपीआई मौजूद नहीं है। देशी वादों के साथ ऐसा करना असंभव है। विनिर्देश ऐसी विधि निर्दिष्ट नहीं करता है।

उपयोगकर्ताभूमि पुस्तकालय ऐसा कर सकते हैं, और यदि आप किसी विशिष्ट इंजन (जैसे v8) को लक्षित कर रहे हैं और प्लेटफ़ॉर्म कोड तक पहुंच है (अर्थात, आप कोर में कोड लिख सकते हैं ) तो आप इसे प्राप्त करने के लिए विशिष्ट उपकरणों (जैसे निजी प्रतीकों) का उपयोग कर सकते हैं । यह सुपर विशिष्ट है, हालांकि उपयोगकर्ता में नहीं है।


4
नोट: मेरा मानना ​​है कि तुल्यकालिक निरीक्षण के लिए उपयोग के मामले कम और बहुत कम हैं, यदि आप अपने ठोस उपयोग के मामले को एक नए प्रश्न में साझा करते हैं, तो पूछते हैं कि इसे बिना तुल्यकालिक निरीक्षण के कैसे प्राप्त किया जा सकता है - अगर कोई नहीं करेगा तो मैं इसका जवाब दूंगा। मुझे हरा दो :)
बेंजामिन ग्रुएनबाम

4
यहां तक ​​कि अगर उपयोग के मामले दुर्लभ हैं, तो इस तरह से कुछ नुकसान क्या होगा? मुझे यह देखने के लिए इस तरह की स्थिति की आवश्यकता होगी कि क्या पिछली नौकरी समाप्त हो गई थी और यदि मैं दूसरी नौकरी का अनुरोध कर सकता था। और मैं सिर्फ एक बाहरी चर सेट नहीं कर सकता क्योंकि ऑब्जेक्ट में नोटिस के बिना मालिकों को बदलने की क्षमता है। क्या अधिक परेशान करने वाली बात यह है कि मैं देख सकता हूँ Node.js की इस जानकारी तक पहुँच है क्योंकि यह मुझे दिखाता है कि जब मैं इसका निरीक्षण करता हूं, लेकिन तार लगाने के अलावा इस पर पहुंचने का कोई तरीका नहीं है ??
Tustin2121

9
इसलिए हमें देशी वादों को फेंक देना चाहिए क्योंकि वे अव्यावहारिक हैं और हमेशा ब्लूबर्ड का उपयोग करते हैं। बढ़िया खबर! मैं मूल वादों का प्रस्ताव कैसे कर सकता हूं कि पदावनत किया जाए और नोड इंजन से बाहर निकाला जाए?
user619271 10

1
बहुत सी बातें, हमें .anyइसके बजाय अनुमान लगाना चाहिए था और एक गलती की क्योंकि मार्क ने जोर दिया। एक के लिए, Promise.race([])हमेशा के लिए लंबित वादा (और त्रुटि नहीं है), आप आम तौर पर पहला सफल वादा चाहते हैं, न कि सिर्फ पहला वादा। वैसे भी, यह वास्तव में पूछे गए सवाल के लिए प्रासंगिक नहीं है - ओपी ने सिंक्रोनस निरीक्षण के बारे में पूछा .raceऔर इसके बारे में और कई कमियों के बारे में नहीं ।
बेंजामिन ग्रुएनबाम

5
@ एरिकोस जो जवाब देता है वह आपको एक वादे की स्थिति का समकालिक निरीक्षण नहीं करने देता है - उदाहरण के लिए MakeQueryablePromise(Promise.resolve(3)).isResolvedयह गलत है लेकिन वादा काफी स्पष्ट रूप से हल हो गया है। इस बात का उल्लेख नहीं है कि "हल" और "पूरा" शब्द का उपयोग गलत तरीके से किया गया है। उस जवाब को करने के लिए आप बस .thenअपने आप को एक हैंडलर जोड़ सकते हैं - जो पूरी तरह से सिंक्रोनस निरीक्षण के बिंदु को याद करता है।
बेंजामिन Gruenbaum

31

यहाँ छवि विवरण दर्ज करें

वादा-स्टेटस-एसिंक्स ट्रिक करता है। यह async है, लेकिन इसे thenहल करने के वादे की प्रतीक्षा करने के लिए उपयोग नहीं करता है ।

const {promiseStatus} = require('promise-status-async');
// ...
if (await promiseStatus(promise) === 'pending') {
    const idle = new Promise(function(resolve) {
        // can do some IDLE job meanwhile
    });
    return idle;
}

4
ओपी ने पूछा कि इसे समकालिक तरीके से कैसे किया जाए
केल्सुन

28

नहीं, कोई सिंक API नहीं है, लेकिन यहां async का मेरा संस्करण promiseState(@ मैथिज्ज़ की मदद से):

function promiseState(p) {
  const t = {};
  return Promise.race([p, t])
    .then(v => (v === t)? "pending" : "fulfilled", () => "rejected");
}

var a = Promise.resolve();
var b = Promise.reject();
var c = new Promise(() => {});

promiseState(a).then(state => console.log(state)); // fulfilled
promiseState(b).then(state => console.log(state)); // rejected
promiseState(c).then(state => console.log(state)); // pending


क्या इस निर्माण के पीछे कोई विशिष्ट तर्क है? यह मुझे अनावश्यक रूप से जटिल लगता है। जहाँ तक मैं इस कार्य को पहचान बता सकता हूँ: Promise.race([ Promise.resolve(p).then(() => "fulfilled", () => "rejected"), Promise.resolve().then(() => "pending") ]); हालाँकि यह मुझे अधिक सुरक्षित लगता है: const t = {}; return Promise.race([p,t]).then(v => v === t ? "pending" : "fulfilled", () => "rejected") और अतिरिक्त वादे करने से बचता है जब तक कि मूल पी लंबित है।
मथिज्स

धन्यवाद @Matthijs! मैंने अपना उत्तर सरल कर दिया है।
जिब

16

आप Promise.resolve के साथ एक दौड़ बना सकते हैं
यह समकालिक नहीं है लेकिन अब होता है

function promiseState(p, isPending, isResolved, isRejected) {
  Promise.race([p, Promise.resolve('a value that p should not return')]).then(function(value) {
    if (value == 'a value that p should not return') {
      (typeof(isPending) === 'function') && isPending();
    }else {
      (typeof(isResolved) === 'function') && isResolved(value);
    }
  }, function(reason) {
    (typeof(isRejected) === 'function') && isRejected(reason);
  });
}

परीक्षण के लिए एक छोटी सी स्क्रिप्ट और अतुल्यकालिक रूप से उनके अर्थ को समझना

var startTime = Date.now() - 100000;//padding trick "100001".slice(1) => 00001
function log(msg) {
  console.log((""+(Date.now() - startTime)).slice(1) + ' ' + msg);
  return msg;//for chaining promises
};

function prefix(pref) { return function (value) { log(pref + value); return value; };}

function delay(ms) {
  return function (value) {
    var startTime = Date.now();
    while(Date.now() - startTime < ms) {}
    return value;//for chaining promises
  };
}
setTimeout(log, 0,'timeOut 0 ms');
setTimeout(log, 100,'timeOut 100 ms');
setTimeout(log, 200,'timeOut 200 ms');

var p1 = Promise.resolve('One');
var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "Two"); });
var p3 = Promise.reject("Three");

p3.catch(delay(200)).then(delay(100)).then(prefix('delayed L3 : '));

promiseState(p1, prefix('p1 Is Pending '), prefix('p1 Is Resolved '), prefix('p1 Is Rejected '));
promiseState(p2, prefix('p2 Is Pending '), prefix('p2 Is Resolved '), prefix('p2 Is Rejected '));
promiseState(p3, prefix('p3 Is Pending '), prefix('p3 Is Resolved '), prefix('p3 Is Rejected '));

p1.then(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
p2.then(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
p3.catch(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
log('end of promises');
delay(100)();
log('end of script');

देरी से परिणाम (0) (देरी में टिप्पणी करें)

00001 end of promises
00001 end of script
00001 Level 1 : One
00001 Level 1 : Three
00001 p1 Is Resolved One
00001 p2 Is Pending undefined
00001 p3 Is Rejected Three
00001 Level 2 : One
00001 Level 2 : Three
00001 delayed L3 : Three
00002 Level 3 : One
00002 Level 3 : Three
00006 timeOut 0 ms
00100 timeOut 100 ms
00100 Level 1 : Two
00100 Level 2 : Two
00101 Level 3 : Two
00189 timeOut 200 ms

और फ़ायरफ़ॉक्स के साथ इस परीक्षण के परिणाम (क्रोम ऑर्डर रखें)

00000 end of promises
00100 end of script
00300 Level 1 : One
00300 Level 1 : Three
00400 p1 Is Resolved One
00400 p2 Is Pending undefined
00400 p3 Is Rejected Three
00400 Level 2 : One
00400 Level 2 : Three
00400 delayed L3 : Three
00400 Level 3 : One
00400 Level 3 : Three
00406 timeOut 0 ms
00406 timeOut 100 ms
00406 timeOut 200 ms
00406 Level 1 : Two
00407 Level 2 : Two
00407 Level 3 : Two

वादा करो


3
इसके बजाय 'a value that p should not return',
प्रोग्रामर

1
@ programmer5000 क्या लाभ है?
मोरित्ज़ श्मिट्ज वी। हुलस्ट

2
@ MoritzSchmitzv.Hüstst एक Symbolअद्वितीय मूल्य होगा, इसलिए आपको कभी भी यह अनुमान नहीं लगाना होगा कि "मूल्य [...] पी वापस नहीं आना चाहिए।" हालाँकि, किसी विशिष्ट ऑब्जेक्ट के संदर्भ में भी काम करेगा।
स्कॉट रुडिगर

7

मूल विधि की पेशकश होने तक आप Node.js में एक (बदसूरत) हैक का उपयोग कर सकते हैं:

util = require('util');

var promise1 = new Promise (function (resolve) {
}

var promise2 = new Promise (function (resolve) {

    resolve ('foo');
}

state1 = util.inspect (promise1);
state2 = util.inspect (promise2);

if (state1 === 'Promise { <pending> }') {

    console.log('pending'); // pending
}

if (state2 === "Promise { 'foo' }") {

    console.log ('foo') // foo
}

3
मैंने इसे एक Promise.prototype.isPending = function(){ return util.inspect(this).indexOf("<pending>")>-1; }
पॉलीफिल में उबाला है

5
वह भयावह है
जॉन वीज़

@JohnWeisz क्या भयावह है पिछड़े संगतता की कमी। मैं एक वादा-एपीआई एपीआई को एक कोडबेस में एकीकृत करने की कोशिश कर रहा हूं, जो मानता है कि सब कुछ समकालिक है। यह या तो कुछ भयावह कर रहा है या कोड की विशाल मात्रा को फिर से लिख रहा है। किसी भी तरह से मैं एक अत्याचार कर रहा हूं।
राठ

4
बस उपयोगprocess.binding('util').getPromiseDetails
अमारा

@ Tustin2121 कुछ संस्करण के लिए यह कुछ इस तरह से विफल हो जाएगा Promise.resolve('<pending>')
user202729

7

नोड में, अनिर्दिष्ट आंतरिक कहें process.binding('util').getPromiseDetails(promise)

> process.binding('util').getPromiseDetails(Promise.resolve({data: [1,2,3]}));
[ 1, { data: [ 1, 2, 3 ] } ]

> process.binding('util').getPromiseDetails(Promise.reject(new Error('no')));
[ 2, Error: no ]

> process.binding('util').getPromiseDetails(new Promise((resolve) => {}));
[ 0, <1 empty item> ]

मैंने इसे इसलिए जोड़ा क्योंकि यह किसी भी मौजूदा उत्तर में नहीं था, और नोड के लिए यह सबसे अच्छा जवाब है। github.com/nodejs/node
amara

6

अपडेट किया गया: 2019

Bluebird.js यह प्रदान करता है: http://bluebirdjs.com/docs/api/isfulfilled.html

var Promise = require("bluebird");
let p = Promise.resolve();
console.log(p.isFulfilled());

यदि आप अपना स्वयं का रैपर बनाना पसंद करते हैं, तो इसके बारे में एक अच्छा ब्लॉग है।

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

यदि आप async कोड को सिंक्रोनाइज़ करना चाहते हैं तो async / प्रतीक्षा एक अच्छा निर्माण है।

await this();
await that();
return 'success!';

एक और उपयोगी कॉल Promise.all () है

var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

जब मैं पहली बार इस उत्तर के लिए पहुंचा, तो वह उपयोग मामला है जिसकी मुझे तलाश थी।


5

आप अपने वादों को इस तरह से लपेट सकते हैं

function wrapPromise(promise) {
  var value, error,
      settled = false,
      resolved = false,
      rejected = false,
      p = promise.then(function(v) {
        value = v;
        settled = true;
        resolved = true;
        return v;
      }, function(err) {
        error = err;
        settled = true;
        rejected = true;
        throw err;
      });
      p.isSettled = function() {
        return settled;
      };
      p.isResolved = function() {
        return resolved;
      };
      p.isRejected = function() {
        return rejected;
      };
      p.value = function() {
        return value;
      };
      p.error = function() {
        return error;
      };
      var pThen = p.then, pCatch = p.catch;
      p.then = function(res, rej) {
        return wrapPromise(pThen(res, rej));
      };
      p.catch = function(rej) {
        return wrapPromise(pCatch(rej));
      };
      return p;
}

5
इससे ईपी को इवेंट लूप के पिछले मोड़ में पहुंच पाने की आवश्यकता होगी । चूंकि .thenहमेशा एसिंक्रोनस रूप से ओपी निष्पादित होता है जो एक ही मोड़ में एक वादे का निरीक्षण करना चाहता है, यहां सही परिणाम नहीं मिलेगा। नोट ओपी ने विशेष रूप से सिंक्रोनस निरीक्षण के बारे में पूछा और उल्लेख किया कि वे पहले से ही अतुल्यकालिक निरीक्षण के बारे में जानते हैं।
बेंजामिन ग्रुएनबाम

@BenjaminGruenbaum: यदि "समान" कोड पर कोड कहा जाता है तो क्या डिफ़ॉल्ट मान नहीं आएगा?
डंडविस

निश्चित रूप से आपको अपने सभी वादों को सृजन के समय पूरा करना होगा। उदाहरण के लिए, उन्हें बनाने और वापस करने वाले कार्यों के अंदर।
स्पाइडरपिग

3
ठीक है, जिस बिंदु पर वे वास्तव में मूल वादे नहीं कर रहे हैं, आप उन्हें उसी तरह से बढ़ा सकते हैं जिस तरह से उन्हें उपवर्ग के साथ बढ़ाया जाना चाहिए, जो आपको ऑब्जेक्ट पर बंदर पैचिंग गुणों के बजाय यह सुरुचिपूर्ण ढंग से करने की अनुमति देगा।
बेंजामिन ग्रुएनबाम

चाहे आप एक वादे का विस्तार करें, जो मैंने दिखाया या सब-क्लासिंग के द्वारा, प्रत्येक मामले में आपको तब भी अपना संस्करण जोड़ना होगा और पकड़ना होगा।
स्पाइडरपिग

5

यह वास्तव में काफी कष्टप्रद है कि यह बुनियादी कार्यक्षमता गायब है। यदि आप नोड का उपयोग कर रहे हैं। तो मुझे दो वर्कअराउंड का पता है, न तो बहुत सुंदर है। नीचे दिए गए दोनों स्निपेट एक ही एपीआई को लागू करते हैं:

> Promise.getInfo( 42 )                         // not a promise
{ status: 'fulfilled', value: 42 }
> Promise.getInfo( Promise.resolve(42) )        // fulfilled
{ status: 'fulfilled', value: 42 }
> Promise.getInfo( Promise.reject(42) )         // rejected
{ status: 'rejected', value: 42 }
> Promise.getInfo( p = new Promise(() => {}) )  // unresolved
{ status: 'pending' }
> Promise.getInfo( Promise.resolve(p) )         // resolved but pending
{ status: 'pending' }

किसी भी चाल का उपयोग करके पिछले दो वादे राज्यों को अलग करने का कोई तरीका प्रतीत नहीं होता है।

1. V8 डीबग API का उपयोग करें

यह वही ट्रिक है जो util.inspectउपयोग करता है।

const Debug = require('vm').runInDebugContext('Debug');

Promise.getInfo = function( arg ) {
    let mirror = Debug.MakeMirror( arg, true );
    if( ! mirror.isPromise() )
        return { status: 'fulfilled', value: arg };
    let status = mirror.status();
    if( status === 'pending' )
        return { status };
    if( status === 'resolved' )  // fix terminology fuck-up
        status = 'fulfilled';
    let value = mirror.promiseValue().value();
    return { status, value };
};

2. सिंक्रोनाइज़्ड माइक्रो-मास्क चलाएं

यह डीबग API से बचा जाता है, लेकिन सभी लंबित माइक्रोटेक और process.nextTickकॉलबैक को समान रूप से होने से कुछ भयावह शब्दार्थ होता है । निरीक्षण किए गए वादे के लिए "अनहेल्ड वादा रिजेक्शन" को कभी भी ट्रिगर होने से रोकने का साइड-इफेक्ट भी है।

Promise.getInfo = function( arg ) {
    const pending = {};
    let status, value;
    Promise.race([ arg, pending ]).then(
        x => { status = 'fulfilled'; value = x; },
        x => { status = 'rejected'; value = x; }
    );
    process._tickCallback();  // run microtasks right now
    if( value === pending )
        return { status: 'pending' };
    return { status, value };
};

यह करना बहुत असुरक्षित है process._tickCallback(या यहां तक ​​कि सादे% RunMicrotick) - यह आपके कोड में बेतरतीब ढंग से चीजों को तोड़ देगा। मैं सख्त काम करने की कोशिश कर रहा था (async कार्यों में नकली टाइमर के लिए, ज्यादातर) और यह नोड पक्ष की ओर से कभी भी स्थिर नहीं था। मैं इस पर काम करना छोड़ दिया। V8 डिबग मिरर एपीआई पूरी तरह से यहां उपयुक्त है।
बेंजामिन Gruenbaum

और .. DeprecationWarning: DebugContext has been deprecated and will be removed in a future version.:( वी 8 की तरह लग रहा है इसे हटा दिया
बेंजामिन Gruenbaum

हम (Node) पूरी तरह से V8 को एपीआई के लिए कह सकते हैं या सीधे एक वादे की स्थिति को देखने के लिए एक एपीआई को उजागर कर सकते हैं - यदि आप github.com/nodejs/promise-use-cases पर एक मुद्दा खोलते हैं तो मैं इसे V8 खुशी से लाऊंगा
बेंजामिन Gruenbaum

1
इस विषय में आगे एक टिप्पणी से पता चला कि एक एपीआई पहले से ही मौजूद है: लंबित के लिए process.binding('util').getPromiseDetails( promise )रिटर्न [ 0, ], [ 1, value ]पूर्ण के लिए, और [ 2, value ]अस्वीकार के लिए।
मैथिज

3

कैविएट: इस विधि में अनिर्दिष्ट नोड.जेएस इंटर्नल का उपयोग किया गया है और इसे बिना किसी चेतावनी के बदला जा सकता है।

नोड में आप सिंक्रोनस का उपयोग करके किसी वादे की स्थिति को निर्धारित कर सकते हैं process.binding('util').getPromiseDetails(/* promise */);

यह लौटेगा:

[0, ] लंबित के लिए,

[1, /* value */] पूरा करने के लिए, या

[2, /* value */] अस्वीकार कर दिया गया।

const pending = new Promise(resolve => setTimeout(() => resolve('yakko')));;
const fulfilled = Promise.resolve('wakko');
const rejected = Promise.reject('dot');

[pending, fulfilled, rejected].forEach(promise => {
  console.log(process.binding('util').getPromiseDetails(promise));
});

// pending:   [0, ]
// fulfilled: [1, 'wakko']
// rejected:  [2, 'dot']

एक सहायक समारोह में इस लपेटकर:

const getStatus = promise => ['pending', 'fulfilled', 'rejected'][
  process.binding('util').getPromiseDetails(promise)[0]
];

getStatus(pending); // pending
getStatus(fulfilled); // fulfilled
getStatus(rejected); // rejected

भीतर से काम नहीं लगता है jest(जो कि केवल एक ही जगह है जो मुझे इसमें दिलचस्पी है, वास्तव में)। फ़ंक्शन मौजूद है, लेकिन हमेशा वापस लौटने लगता है undefined। मुझे कैसे पता चलेगा कि क्या गलत है?
एडम बार्न्स

हम्म, मुझे याद है कि यह भीतर काम कर रहा है mocha; jestहालांकि इसके साथ कभी कोशिश नहीं की । हो सकता है कि यहां एक नया प्रश्न शुरू हो रहा हो और इसमें आपके Node.js संस्करण के साथ-साथ jestसंस्करण भी शामिल हो?
स्कॉट रुडिगर

ऐसा कुछ नहीं जो मुझे किसी बड़ी बात में दिलचस्पी है, दुर्भाग्य से। मैं मूल रूप से अपने मैन्युअल-रिज़ॉल्वेबल / अस्वीकार्य परीक्षण के लिए पवित्रता की तलाश कर Promiseरहा था जो कि मैं केवल परीक्षण सामग्री का उपयोग कर रहा था जो कि Promiseलंबित होने पर होना चाहिए , लेकिन मुझे लगा कि जब तक मैंने लिखा, काम करता है, तब तक परीक्षण करने की आवश्यकता नहीं है इसके अलावा जो इस पर निर्भर करता है।
एडम बार्न्स

2

आप क्या कर सकते हैं, राज्य को संग्रहीत करने के लिए एक चर का उपयोग करना है, मैन्युअल रूप से उस चर में राज्य को सेट करें, और उस चर की जांच करें।

var state = 'pending';

new Promise(function(ff, rjc) {
  //do something async

  if () {//if success
    state = 'resolved';

    ff();//
  } else {
    state = 'rejected';

    rjc();
  }
});

console.log(state);//check the state somewhere else in the code

बेशक, इसका मतलब है कि आपके पास वादे के मूल कोड तक पहुंच होनी चाहिए। यदि आप नहीं करते हैं, तो आप कर सकते हैं:

var state = 'pending';

//you can't access somePromise's code
somePromise.then(function(){
  state = 'resolved';
}, function() {
  state = 'rejected';
})

console.log(state);//check the promise's state somewhere else in the code

मेरा समाधान अधिक कोडिंग है, लेकिन मुझे लगता है कि आप शायद आपके द्वारा उपयोग किए जाने वाले प्रत्येक वादे के लिए ऐसा नहीं करेंगे।



2

आप Promise.prototype के लिए एक विधि जोड़ सकते हैं। यह इस तरह दिख रहा है:

संपादित: पहला समाधान ठीक से काम नहीं कर रहा है, जैसे यहां अधिकांश उत्तर। यह "लंबित" को तब तक लौटाता है जब तक कि अतुल्यकालिक फ़ंक्शन ".then" को लागू नहीं किया जाता है, जो तुरंत नहीं होता है। (यह Promise.race का उपयोग कर समाधान के बारे में है)। मेरा दूसरा समाधान इस समस्या को हल करता है।

if (window.Promise) {
    Promise.prototype.getState = function () {
        if (!this.state) {
            this.state = "pending";
            var that = this;
            this.then(
                function (v) {
                    that.state = "resolved";
                    return v;
                },
                function (e) {
                    that.state = "rejected";
                    return e;
                });
        }
        return this.state;
    };
}

आप इसे किसी भी प्रॉमिस पर इस्तेमाल कर सकते हैं। उदाहरण के तौर पर:

myPromise = new Promise(myFunction);
console.log(myPromise.getState()); // pending|resolved|rejected

दूसरा (और सही) समाधान:

if (window.Promise) {
    Promise.stateable = function (func) {
        var state = "pending";
        var pending = true;
        var newPromise = new Promise(wrapper);
        newPromise.state = state;
        return newPromise;
        function wrapper(resolve, reject) {
            func(res, rej);
            function res(e) {
                resolve(e);
                if (pending) {
                    if (newPromise)
                        newPromise.state = "resolved";
                    else
                        state = "resolved";
                    pending = false;
                }
            }
            function rej(e) {
                reject(e);
                if (pending) {
                    if (newPromise)
                        newPromise.state = "rejected";
                    else
                        state = "rejected";
                    pending = false;
                }
            }
        }
    };
}

और इसका उपयोग करें:

सूचना : इस समाधान में आपको "नए" ऑपरेटर का उपयोग करने की आवश्यकता नहीं है।

myPromise = Promise.stateable(myFunction);
console.log(myPromise.state); // pending|resolved|rejected

1

यहाँ QueryablePromise का एक और fleshed es6 संस्करण है, जो पहले रिज़ॉल्यूशन के बाद चेन को पकड़ने की क्षमता और तुरंत हल करने या देशी प्रॉमिस के साथ एपी को सुसंगत रखने के लिए अस्वीकार या अस्वीकार करने की अनुमति देता है।

const PROMISE = Symbol('PROMISE')
const tap = fn => x => (fn(x), x)
const trace = label => tap(x => console.log(label, x))

class QueryablePromise {
  resolved = false
  rejected = false
  fulfilled = false
  catchFns = []
  constructor(fn) {
    this[PROMISE] = new Promise(fn)
      .then(tap(() => {
        this.fulfilled = true
        this.resolved = true
      }))
      .catch(x => {
        this.fulfilled = true
        this.rejected = true
        return Promise.reject(x)
      })
  }
  then(fn) {
    this[PROMISE].then(fn)
    return this
  }
  catch(fn) {
    this[PROMISE].catch(fn)
    return this
  }
  static resolve(x) {
    return new QueryablePromise((res) => res(x))
  }
  static reject(x) {
    return new QueryablePromise((_, rej) => rej(x))
  }
}

const resolvedPromise = new QueryablePromise((res) => {
  setTimeout(res, 200, 'resolvedPromise')
})

const rejectedPromise = new QueryablePromise((_, rej) => {
  setTimeout(rej, 200, 'rejectedPromise')
})

// ensure our promises have not been fulfilled
console.log('test 1 before: is resolved', resolvedPromise.resolved)
console.log('test 2 before: is rejected', rejectedPromise.rejected)


setTimeout(() => {
  // check to see the resolved status of our promise
  console.log('test 1 after: is resolved', resolvedPromise.resolved)
  console.log('test 2 after: is rejected', rejectedPromise.rejected)
}, 300)

// make sure we can immediately resolve a QueryablePromise
const immediatelyResolvedPromise = QueryablePromise.resolve('immediatelyResolvedPromise')
  // ensure we can chain then
  .then(trace('test 3 resolved'))
  .then(trace('test 3 resolved 2'))
  .catch(trace('test 3 rejected'))

// make sure we can immediately reject a QueryablePromise
const immediatelyRejectedPromise = QueryablePromise.reject('immediatelyRejectedPromise')
  .then(trace('test 4 resolved'))
  .catch(trace('test 4 rejected'))
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>


1

awaitमुहावरेदार प्रोटोटाइप के साथ @ जिब के उत्तर का उपयोग ।

Object.defineProperty(Promise.prototype, "state", {
    get: function(){
        const o = {};
        return Promise.race([this, o]).then(
            v => v === o ? "pending" : "resolved",
            () => "rejected");
    }
});

// usage: console.log(await <Your Promise>.state);
(async () => {
    console.log(await Promise.resolve(2).state);  // "resolved"
    console.log(await Promise.reject(0).state);   // "rejected"
    console.log(await new Promise(()=>{}).state); // "pending"
})();

ध्यान दें कि यह async फ़ंक्शन तुरंत "लगभग" को समानार्थी फ़ंक्शन की तरह निष्पादित करता है (या वास्तव में संभवतः तुरंत हो सकता है)।


1

2019:

यह करने का सरल तरीका है कि जैसा कि मुझे पता है thenable, वादा या किसी भी async नौकरी के आसपास सुपर पतली आवरण।

const sleep = (t) => new Promise(res => setTimeout(res,t));
const sleeping = sleep(30);

function track(promise){
    let state = 'pending';
    promise = promise.finally( _=> state ='fulfilled');
    return {
        get state(){return state},
        then: promise.then.bind(promise), /*thentable*/
        finally:promise.finally.bind(promise),
        catch:promise.catch.bind(promise),
    }
}


promise = track(sleeping);
console.log(promise.state) // pending

promise.then(function(){
    console.log(promise.state); // fulfilled
})

1

आप extendएक नया क्वेरी करने योग्य वादा वर्ग बनाने के लिए वादा क्लास कर सकते हैं ।

आप अपना उपवर्ग बना सकते हैं, कह सकते हैं कि QueryablePromiseमूल रूप से उपलब्ध Promiseवर्ग से विरासत में , जिसके उदाहरणों पर उस पर एक statusसंपत्ति उपलब्ध होगी जिसका उपयोग आप वादे की वस्तुओं की स्थिति को तुल्यकालिक रूप से क्वेरी करने के लिए कर सकते हैं । इसका कार्यान्वयन नीचे देखा जा सकता है या बेहतर स्पष्टीकरण के लिए इसे संदर्भित कर सकता है ।

class QueryablePromise extends Promise {
  constructor (executor) {
    super((resolve, reject) => executor(
      data => {
        resolve(data)
        this._status = 'Resolved'
      },
      err => {
        reject(err)
        this._status = 'Rejected'
      },
    ))
    this._status = 'Pending'
  }

  get status () {
    return this._status
  }
}
 
// Create a promise that resolves after 5 sec 
var myQueryablePromise = new QueryablePromise((resolve, reject) => {
  setTimeout(() => resolve(), 5000)
})

// Log the status of the above promise every 500ms
setInterval(() => {
  console.log(myQueryablePromise.status)
}, 500)


दुर्भाग्य से, कोई भी मौजूदा एपीआई इस नए वर्ग को नहीं लौटाएगा। आप कैसे कल्पना कर रहे हैं कि लोग इसका उपयोग कर रहे हैं?
जिब

@jib आपकी प्रतिक्रिया के लिए धन्यवाद। आपका क्या मतलब है कि कोई भी एपीआई इस वर्ग को वापस नहीं करेगा। :(
उत्कर्षप्रमोदगुप्ता

कोई मौजूदा API इसे वापस नहीं करेगा, क्योंकि उन्हें इसे वापस लिखने के लिए लिखना होगा, है ना? उदाहरण के लिए, अगर मैं fetchइसे एक देशी वादा वापस करूंगा। आपकी कक्षा कैसे मदद करेगी?
जिब

ठीक है, क्या हम अपने नए QuerablePromise की तरह उस कॉल को नहीं लपेट सकते const queryableFetch = new QueryablePromise((resolve, reject) => {fetch(/.../).then((data) => resolve(data)) })? या, वहाँ उस के साथ एक मुद्दा है? : /
उत्कर्षप्रमोदगुप्ता

यह काम करना चाहिए, बस , err => reject(err)दूसरे आर्ग के रूप में मत भूलना thenया यह त्रुटियों को सही ढंग से प्रचारित नहीं करेगा (कारणों के बीच यह वादा निर्माता विरोधी पैटर्न माना जाता है )। यह वास्तव में समकालिक नहीं है (जैसे पहले से हल किए गए वादे का पता नहीं लगाएगा), लेकिन शायद उन मामलों में उपयोगी है जहां आप कॉलर को नियंत्रित नहीं करते हैं और जवाब तुरंत चाहिए।
जिब

1

एक और है सुरुचिपूर्ण पता चल सके कि एक वादा अभी भी स्ट्रिंग के लिए पूरी वस्तु परिवर्तित करके सिर्फ लंबित है और इस तरह का निरीक्षण की मदद से यह जाँच है और hacky तरीका: util.inspect(myPromise).includes("pending")

Node.js 8,9,10,11,12,13 पर परीक्षण किया गया

यहाँ एक पूर्ण उदाहरण है

const util = require("util")

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

(async ()=>{
  let letmesleep = sleep(3000)
  setInterval(()=>{
    console.log(util.inspect(letmesleep).includes("pending"))
  },1000)
})()

परिणाम:

true
true
false
false
false

0

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

async function getClient() {
  let client, resolved = false;
  try {
    client = await new Promise((resolve, reject) => {
      let client = new Client();

      let timer = setTimeout(() => {
         reject(new Error(`timeout`, 1000));
         client.close();
      });

      client.on('ready', () => {
        if(!resolved) {
          clearTimeout(timer);
          resolve(client);
        }
      });

      client.on('error', (error) => {
        if(!resolved) {
          clearTimeout(timer);
          reject(error);
        }
      });

      client.on('close', (hadError) => {
        if(!resolved && !hadError) {
          clearTimeout(timer);
          reject(new Error("close"));
        }
      });
    });

    resolved = true;
  } catch(error) {
    resolved = true;
    throw error;
  }
  return client;
}

0

मैंने थोड़ा npm पैकेज, वादा-मूल्य लिखा है, जो एक resolvedध्वज के साथ एक वादा आवरण प्रदान करता है :

https://www.npmjs.com/package/promise-value

यह भी वादा मूल्य (या त्रुटि) के लिए तुल्यकालिक पहुँच देता है। यह प्रतिमान ऑब्जेक्ट में परिवर्तन नहीं करता है, केवल विस्तार पैटर्न के बजाय रैप के बाद।


0

यह पुराना सवाल है लेकिन मैं कुछ ऐसा ही करने की कोशिश कर रहा था। मुझे एन वर्कर्स को रखने की जरूरत है। वे एक वादे में संरचित हैं। मुझे स्कैन करने और देखने की आवश्यकता है कि क्या वे हल किए गए हैं, अस्वीकार किए गए हैं या अभी भी लंबित हैं। यदि हल किया जाता है, तो मुझे मूल्य की आवश्यकता है, यदि अस्वीकार किया गया है तो समस्या को ठीक करने या लंबित करने के लिए कुछ करें। यदि हल या अस्वीकार कर दिया गया है तो मुझे n चलते रहने के लिए एक और कार्य शुरू करने की आवश्यकता है। मैं Promise.all या Promise.race के साथ इसे करने का एक तरीका नहीं समझ सकता क्योंकि मैं एक सरणी में काम करने के वादे रखता हूं और उन्हें हटाने का कोई तरीका नहीं खोज सकता। तो मैं एक कार्यकर्ता बनाता हूं जो चाल करता है

मुझे एक वादा जनरेटर फ़ंक्शन की आवश्यकता है जो एक वादा लौटाता है जो आवश्यक के रूप में हल या अस्वीकार करता है। यह एक फ़ंक्शन द्वारा कहा जाता है जो यह पता लगाने के लिए रूपरेखा तैयार करता है कि वादा क्या कर रहा है।

जनरेटर के नीचे कोड में बस सेटटाइमआउट के आधार पर एक वादा वापस किया जाता है।

यह रहा

//argObj should be of form
// {succeed: <true or false, nTimer: <desired time out>}
function promiseGenerator(argsObj) {
  let succeed = argsObj.succeed;          
  let nTimer = argsObj.nTimer;
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (succeed) {
        resolve('ok');
      }
      else {
        reject(`fail`);
      }
    }, nTimer);
  })

}

function doWork(generatorargs) {
  let sp = { state: `pending`, value: ``, promise: "" };
  let p1 = promiseGenerator(generatorargs)
    .then((value) => {
      sp.state = "resolved";
      sp.value = value;
    })
    .catch((err) => {
      sp.state = "rejected";
      sp.value = err;
    })
  sp.promise = p1;
  return sp;
}

doWork वादे और उसके राज्य और वापस लौटे मूल्य वाली एक वस्तु देता है।

निम्न कोड एक लूप चलाता है जो राज्य का परीक्षण करता है और इसे चलाने वाले 3 श्रमिकों पर रखने के लिए नए श्रमिक बनाता है।

let promiseArray = [];

promiseArray.push(doWork({ succeed: true, nTimer: 1000 }));
promiseArray.push(doWork({ succeed: true, nTimer: 500 }));
promiseArray.push(doWork({ succeed: false, nTimer: 3000 }));

function loopTimerPromise(delay) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('ok');
    }, delay)
  })
}

async function looper() {
  let nPromises = 3;      //just for breaking loop
  let nloop = 0;          //just for breaking loop
  let i;
  //let continueLoop = true;
  while (true) {
    await loopTimerPromise(900);  //execute loop every 900ms
    nloop++;
    //console.log(`promiseArray.length = ${promiseArray.length}`);
    for (i = promiseArray.length; i--; i > -1) {
      console.log(`index ${i} state: ${promiseArray[i].state}`);
      switch (promiseArray[i].state) {
        case "pending":
          break;
        case "resolved":
          nPromises++;
          promiseArray.splice(i, 1);
          promiseArray.push(doWork({ succeed: true, nTimer: 1000 }));
          break;
        case "rejected":
          //take recovery action
          nPromises++;
          promiseArray.splice(i, 1);
          promiseArray.push(doWork({ succeed: false, nTimer: 500 }));
          break;
        default:
          console.log(`error bad state in i=${i} state:${promiseArray[i].state} `)
          break;
      }
    }
    console.log(``);
    if (nloop > 10 || nPromises > 10) {
      //should do a Promise.all on remaining promises to clean them up but not for test
      break;
    }
  }
}

looper();

नोड.जेएस में परीक्षण किया गया

BTW इस जवाब में इतना नहीं है, लेकिन इसी तरह के विषयों पर दूसरों में, मैं इसे नफरत करता हूं जब कोई कहता है कि "आप नहीं समझते" या "यह कैसे काम करता है" मैं आम तौर पर मान लेता हूं कि प्रश्नकर्ता को पता है कि वे क्या चाहते हैं। बेहतर तरीके से सुझाव देना शानदार है। वादे कैसे काम करते हैं, इसका एक रोगी स्पष्टीकरण भी अच्छा होगा।


-1

मैंने इस समाधान को सरल पाया और मुझे मूल वादों का उपयोग जारी रखने की अनुमति दी, लेकिन उपयोगी तुल्यकालिक जांचों को जोड़ा। मुझे भी एक पूरे वादे के पुस्तकालय में खींचने की जरूरत नहीं थी।

गुफा: यह तभी काम करता है जब वर्तमान निष्पादन थ्रेड में कुछ प्रकार का ब्रेक होता है ताकि वादों को तुल्यकालिक निर्माणों की जांच करने से पहले निष्पादित किया जा सके। कि मैंने शुरू में सोचा था की तुलना में यह अधिक सीमित उपयोगिता बनाता है - अभी भी मेरे उपयोग के मामले के लिए उपयोगी है (धन्यवाद बेंजामिन Gruenbaum यह इंगित करने के लिए)

/**
 * This function allow you to modify a JS Promise by adding some status properties.
 * Based on: http://stackoverflow.com/questions/21485545/is-there-a-way-to-tell-if-an-es6-promise-is-fulfilled-rejected-resolved
 * But modified according to the specs of promises : https://promisesaplus.com/
 */
function MakeQuerablePromise(promise) {
    // Don't modify any promise that has been already modified.
    if (promise.isFulfilled) return promise;

    // Set initial state
    var isPending = true;
    var isRejected = false;
    var isFulfilled = false;

    // Observe the promise, saving the fulfillment in a closure scope.
    var result = promise.then(
        function(v) {
            isFulfilled = true;
            isPending = false;
            return v; 
        }, 
        function(e) {
            isRejected = true;
            isPending = false;
            throw e; 
        }
    );

    result.isFulfilled = function() { return isFulfilled; };
    result.isPending = function() { return isPending; };
    result.isRejected = function() { return isRejected; };
    return result;
}

wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); 
setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);

Https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved से उनके जवाब के आधार पर वहाँ एक तरीका है यह बताएं कि क्या ES6 वादा पूरा / अस्वीकार / हल किया गया है?


जैसा कि मेरे उत्तर पर आपकी टिप्पणी में जोड़ा गया है - यह पूरी तरह से गलत है: यह आपको एक वादे की स्थिति का समकालिक निरीक्षण नहीं करने देता है - उदाहरण के लिए MakeQueryablePromise(Promise.resolve(3)).isResolvedयह गलत है लेकिन वादा काफी स्पष्ट रूप से हल हो गया है। इस बात का उल्लेख नहीं है कि "हल" और "पूरा" शब्द का उपयोग गलत तरीके से किया गया है। उस जवाब को करने के लिए आप बस .thenअपने आप को एक हैंडलर जोड़ सकते हैं - जो पूरी तरह से सिंक्रोनस निरीक्षण के बिंदु को याद करता है।
बेंजामिन Gruenbaum

मैं देख रहा हूं कि आप क्या कह रहे हैं और आप एक अच्छा मुद्दा बनाते हैं। जेएस की एकल पिरोया हुई प्रकृति यह नहीं है? आपको हल के रूप में चिह्नित किए जाने वाले वादे के लिए वर्तमान निष्पादन में एक ब्रेक लगाना होगा। let wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);जब तक आप ऐसा करते हैं, यह अच्छी तरह से काम करता है। लेकिन आपको इस तथ्य को समझना होगा कि इसके लिए उपयोगी होना चाहिए। मैं उस चेतावनी के साथ विवरण को अपडेट करूंगा। मैं यह भी मानता हूं कि फ़ंक्शन नामकरण बेहतर / अधिक मुहावरेदार हो सकता है।
अक्रिकोस

लेकिन उस बिंदु पर आप सिर्फ thenमूल वादा कर सकते हैं और उसी चीज को पूरा कर सकते हैं क्योंकि यह वैसे भी अतुल्यकालिक है। वहाँ के साथ एक तरीका है process.binding('util').getPromiseDetailsकि काम करने लगता है, लेकिन यह एक निजी एपीआई का उपयोग कर रहा है
बेंजामिन Gruenbaum

यह हर समय होने के लिए अप्रिय है और कोड को समझना अधिक कठिन बनाता है। खासतौर से तब, जब मुझे इस बात की परवाह है कि क्या वादे को अस्वीकार कर दिया गया है या नहीं - इसलिए मेरे विकल्प हैं कि या तो उस राज्य को कहीं और स्टोर करें या ऐसा कुछ करें। मैं स्वीकार करता हूं कि मैंने अपना स्वयं का पोस्ट करने से पहले अन्य समाधानों को पूरी तरह से यहां नहीं पढ़ा - इसके लिए माफी। यह समस्या मैं पहले सोचा था की तुलना में अच्छा है।
अक्रिकोस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.