Definitelytyped: بلوبيرد 3.0: كيفية استخدامه كحمل زائد للوعد العالمي؟

تم إنشاؤها على ٢٤ أغسطس ٢٠١٦  ·  44تعليقات  ·  مصدر: DefinitelyTyped/DefinitelyTyped

مرحبا جميعا!

أنا أستخدم بلوبيرد كبديل لكائن الوعد العالمي. لقد حاولت تحديث ملفات Typedefs إلى أحدث إصدار ، تم نشره بواسطة lhecker ، وواجهت مشكلة: لا يتم تحميل Promsie العالمي بشكل زائد الآن بشكل افتراضي.
كيف الكاميرا أحقق السلوك السابق؟ ربما يمكن أن يكون لدينا Bluebird-global.d.ts ، على سبيل المثال؟

التعليق الأكثر فائدة

أهلا يا أصدقاء،

@types/bluebird-global متاح الآن. تستخدم هذه الكتابة @types/bluebird@^3.0 تحت غطاء محرك السيارة وتسمح لك باستخدام أساليب Bluebird على Promise العالمية (أي أن تجميع TS لا يفشل).

يرجى قراءة هذا لمعرفة كيفية استخدامه.

ال 44 كومينتر

حسنًا ، IMHO لم تكن تعريفات Bluebird السابقة حلاً جيدًا أيضًا ، لأنها تسربت بشكل كبير إلى مساحة الاسم العالمية وأعتقد أنها كانت فكرة جيدة لتقليل الجهود الزائدة عن الحاجة.

الطريقة التي عملت بها التعريفات السابقة هي تحديد declare var Promise: PromiseConstructor; بينما PromiseConstructor كانت واجهة Bluebird السابقة (المحددة عالميًا).

أي إذا قمت بإنشاء ملف *.d.ts محلي وأضفت شيئًا كهذا ، فربما يعمل؟

import Bluebird = require("bluebird");
declare var Promise: Bluebird<any>;

ربما تعمل ربما؟

للاسف لا. لأن لدي الكثير من التعليمات البرمجية ، والتي تمت كتابتها على النحو التالي:

declare function doLoadData(): Promise<Data>

كما ترى ، ترجع الدالة Promise<T> ، وهو المعيار Promsie ، وليس بلوبيرد. بالإعلان var Promise: Bluebird<any> سأزيد تحميل مُنشئ Promise القياسي ، وليس الواجهة.

عدت إلى كتابة 2.0 لهذا السبب.

Strate آه لعنة لقد كتبت تعليقًا مطولًا حول ما أفكر فيه حول هذا وما يجب أن نحاول القيام به. لكن يبدو أنني نسيت أن أقدمها وضاعت أخيرًا ...

يبدو أن الكثير من الناس لديهم هذه المشكلة.

لقد أنشأت الريبو الذي يوضح المشكلة: https://github.com/d-ph/typescript-bluebird-as-global-promise

استنساخ git && npm install && npm run tsc

المشكلة:
تتم كتابة ملفات الطرف الثالث d.ts مقابل Promise . يتم تحديد Promise هذا إما عن طريق lib.es6.d.ts الخاص بـ printcript (عندما "target": "es6" ) أو بواسطة libs الأخرى ، على سبيل المثال core-js (شائع جدًا ، عند التحويل إلى es5 باستخدام الكتابة المطبوعة) . لم يتم الإعلان عن أحدث bluebird.d.ts على أنه Promise عالميًا ، على الرغم من أن bluebird.js يعرض نفسه على أنه Promise عالميًا.

نتيجة:
لا يمكن للمطورين استخدام وظائف بلوبيرد في الوعود التي تم إرجاعها من كود الطرف الثالث (فشل التجميع).

نتيجة متوقعة:
يمكن للمطورين استخدام وظائف بلوبيرد في الوعود التي تم إرجاعها من كود الطرف الثالث (نجح التجميع).

لست متأكدا من هو المشرف على كتابات بلوبيرد. lhecker ، أنت الشخص غير المحظوظ الذي تم إرجاعه git blame . هل يمكن أن تخبرنا ، ما هو السبب المفضل لاستخدام كتابات بلوبيرد بهذه الطريقة ، أن مشروع جيثب ، الذي ربطته أعلاه ، يجمع؟

جولات المشي الحالية:

  1. الأقذر. لا تقم أبدًا باستيراد بلوبيرد ولا تستخدم كتابات بلوبيرد أبدًا. بالنسبة إلى وظائف Bluebird Promise ، استخدم هذا: Promise["config"]({}); Promise.resolve("foo")["finally"](() => { console.log("lol"); }) لإسكات المترجم. أي استخدم عامل الوصول إلى الصفيف: [""]
  2. قذر ومزعج. في كل ملف ts إدخال في تطبيقك أضف هذين السطرين:
import * as Bluebird from 'bluebird';
declare global { export interface Promise<T> extends Bluebird<T> {} }

لوظائف Bluebird الثابتة ، استخدم Bluebird.config({}) بدلاً من Promise.config({}) .

الجانب السلبي هو أن IDEs تكافح لتفسير هذا الاختراق بشكل صحيح.

حسنًا ... كان من غير المتوقع بالنسبة لي أن تواجهكم مشاكل مع هذا ، لأنكم جميعًا تستخدمون Bluebird بطريقة لا أفعلها أنا والعديد من الآخرين. في الحقيقة لم أكتب الكتابات بنفسي! لقد قمت ببساطة بنسخ النسخ الموجودة فقط لـ 3.0 من هنا ، لأن وجود أي كتابة لـ 3.0 أفضل من عدم وجود أي كتابة ، أليس كذلك؟

الشيء هو أن الاتجاه الحالي الذي يتجه إليه TypeScript هو modules > globals وهو أمر أوافق عليه حقًا. ولكن هذا يعني أيضًا أن الوحدات النمطية لا يجب أن تقوم بتعديل الكائنات العامة مطلقًا ، خاصة إذا كنت تعتقد أن Bluebird لا يحل محل Promise العالمي في كل حالة! أو لنضعها على هذا النحو:

ماذا يحدث لـ "نوع الأمان" إذا اتصلت بـ Promise.noConflict() حرفياً في أي مكان في شفرتك؟ سيعيد النوع Promise العالمي إلى النوع الأصلي وسيؤدي إلى تعطل الكود ، على الرغم من أن tsc أخبرك أن كل شيء على ما يرام.

لذا نعم ... @ d-ph. الجولة الثانية الخاصة بك هي ما يجب أن تفكر في القيام به طوال الوقت ، لأنه يتماشى مع روح أنظمة الوحدات. لكني أعلم أن هذا هو الحل الأمثل للمكتبات ، في حين أنه _ يمكن أن يكون مزعجًا حقًا للتطبيقات. أوافق على أن أنظمة التطبيقات يجب أن تكون بالتأكيد قادرة على الأقل على استبدال الكائن العالمي Promise ومن ثم أن يكون لديها أيضًا المطابقات المطابقة لحالة الاستخدام هذه كما كانت متوفرة في الإصدار 2.0.

في النهاية ، أعتقد أنه في ضوء أيديولوجية TypeScript التي توسع النوع العالمي Promise ، يجب أن يتم ذلك بعناية شديدة (تذكر مشكلة noConflict() وما إلى ذلك) وإذا كان الأمر كذلك فقط عند الاشتراك.

طريقة IMO للمضي قدمًا هي كتابة ملف bluebird-global.d.ts (أو ما شابه) من نوع ما والذي يمتد إلى كائن Promise العام مع تعريفات الواجهة نفسها الموجودة في ملف bluebird.d.ts . وإذا كنت بحاجة إلى استخدام هؤلاء ، فيجب عليك استيرادهم صراحةً بدلاً من تضمينهم دائمًا. بهذه الطريقة يمكنك الحصول على طباعة آمنة وصحيحة لمعظم حالات الاستخدام وخاصة عند كتابة المكتبات ، مع إمكانية الوصول إلى المزايا الإضافية للكتابة فوق التطبيقات العالمية Promise في التطبيقات.

إذا كنت تعتقد أن هذه الفكرة جيدة وإذا كان لديك بعض وقت الفراغ ، فسيكون من الرائع إذا كان بإمكانك إنشاء علاقات عامة. أنا متأكد من أن الكثيرين سيكونون سعداء حقًا بمثل هذه المساهمة. 🙂

أنا أصيغها بهذه الطريقة لأنني حاليًا لست في وضع يسمح لي بكتابة تلك الكتابة ، بسبب ضيق الوقت ولست بحاجة إلى مثل هذه الكتابة في الوقت الحالي. آمل أن تتمكن من فهم ذلك.

lhecker أعتقد أنني يمكن أن أتفق معك. لأنه إذا كان لدينا تجاوز عالمي لوعد بلوبيرد ، فسنقوم فقط باختراق مترجم الحروف ، ولكن ليس العالم الحقيقي. على سبيل المثال ، مع تجاوز Promise ، سوف تعتقد أن الكتابة على الورق المطبوع عليها fetch تقوم بإرجاع Bluebird:

import `whatwg-fetch`;
let result = fetch("anyurl"); // this is NOT bluebird promise, but typescript think that it is.

بدون التفاف fetch إلى بلوبيرد Promise.resolve لن تحصل ، على سبيل المثال ، .finally على result :

import `whatwg-fetch`;
fetch("anyurl").then().finally() // goes to runtime error with overriden global promise, but should be compile error.

لذلك ، أعتقد أن استيراد bluebird بشكل صريح عند كل استخدام هو الحل الأفضل:

import Promise from "bluebird";
import `whatwg-fetch`;
Promise.resolve(fetch("anyurl")).then().catch() // no compile error, no runtime error

سأقوم بإعادة تشكيل الكود الخاص بي.

شكرا لإجابتك ، lhecker .

أنا أتفق مع كل ما قلته. وأحب حل Strate المتمثل في تغليف كود الطرف الثالث بطريقة Promise.resolve() ، لتحويل وعد es6 إلى Bluebird (أو Bluebird إلى Bluebird ، لأنني أرغب في الحفاظ على وعد Bluebird عالميًا في وقت التشغيل ، لذلك لا أفعل لا داعي للاعتماد على كود طرف ثالث للتعامل مع أخطائهم بشكل صحيح ، ولكن هذا بجانب النقطة).

يبدو أنني لم أكن أعرف كيفية القيام بذلك بشكل صحيح. ما أعتقد أن الآخرين سيستفيدون منه هو المزيد من التوثيق حول كيفية التعامل مع هذه المشكلة ، لأن كل شخص قادم من عالم برمجة المستعرض (على عكس: من nodejs / typecript) يصل إليه بعد أن:

  1. npm install <absolutely everything that uses es6 promise>
  2. npm install bluebird @types/bluebird
  3. استخدم كود الجهة الخارجية مع الكتابة المطبوعة

سأستفيد أيضًا من الحصول على قسم "كيفية الاستخدام في حالة كتابة رمز جهة خارجية مقابل وعد es6" الموثق في مكان ما للرجوع إليه في المستقبل. أي وجود

import * as Bluebird from 'bluebird';
declare global { export interface Promise<T> extends Bluebird<T> {} }

و

import * as Promise from 'bluebird';
import { Observable } from "rxjs";

let observable = Promise.resolve(new Observable<number>().toPromise());

في الملف التمهيدي أو في كتلة المستندات أعلى ملف bluebird.d.ts.

ما رأيك؟

لقد أكملت الانتقال من التجاوز العالمي لـ Promise إلى بلوبيرد ، ووجدت بعض المشكلات ، حيث تقوم مكتبات الطرف الثالث بإرجاع ES6 Promise ، والتي تم تصنيفها على أنها Bluebird. لذا ، يؤدي إجراء هذه الخطوة إلى تنظيف قاعدة الشيفرة الخاصة بي أيضًا. أود أن أوصي الجميع بالانتقال من التحميل الزائد العالمي بمقدار Promise . هتافات :)

أفهم modules > globals لكن دعنا نقول من أجل الجدل (و / أو الواقع) أنني أعمل على متصفح SPA كبير الحجم وقد تم تكليفي باستخدام Bluebird باعتباره Promise polyfill.

أحاول إصلاح bluebird-global.d.ts الذي اقترحه lhecker مع المحتوى من @ d-ph:

import * as Bluebird from 'bluebird';
declare global { export interface Promise<T> extends Bluebird<T> {} }

لقد قمت بتثبيته عبر typings مما أدى إلى الحصول على typings/modules/bluebird-global/index.d.ts :

// Generated by typings
// Source: src/bluebird-global.d.ts
declare module 'bluebird-global' {
// via https://github.com/DefinitelyTyped/DefinitelyTyped/issues/10801
import * as Bluebird from 'bluebird';
global { export interface Promise<T> extends Bluebird<T> {} }
}

ومع ذلك ، عندما أحاول بناء كل شيء ، يشكو TypeScript (v1.8.2):

ERROR in /path/to/typings/modules/bluebird-global/index.d.ts
(6,27): error TS2665: Module augmentation cannot introduce new names in the top level scope.

ERROR in /path/to/src/bluebird-global.d.ts
(2,35): error TS2665: Module augmentation cannot introduce new names in the top level scope.

ألقيت نظرة على مثال MS مقابل global-modifying-module.ts
https://www.typescriptlang.org/docs/handbook/decerson-files/templates/global-modifying-module-d-ts.html

ومشكلة TS المتعلقة برسالة الخطأ هذه
https://github.com/Microsoft/TypeScript/issues/6722

لكنني في حيرة مما يجب أن أفعله. هل أستطيع مساعدتك؟

مرحبا.

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

// declare global {
//     export interface Promise<T> extends Bluebird<T> {}
// }

يجمع؟

ضع في اعتبارك أن الريبو الخاص بي يستخدم TS 2 (وهو الآن مستقر) وقلت أنك تستخدم 1.8.2. فقط تحقق مما يحدث عند ترقية TS إلى 2.

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

أريد أيضًا أن أكون قادرًا على "تسجيل" تنفيذ Bluebird Promise باعتباره Promise العالمي. قرأت هذا الموضوع بأكمله ولكني لا أتبع جزءًا واحدًا. الجزء الذي يشير إلى أن مكتبات الطرف الثالث ستستمر في إرجاع التنفيذ الأصلي (على سبيل المثال غير Bluebird) Promise . كيف يمكن أن يكون هذا ، عندما يكون كود الطرف الثالث في مرحلة ما يستدعي المُنشئ Promise ( new Promise(...) ) الذي تم استبداله بتطبيق Bluebird على المستوى العالمي؟

<script src="//.../bluebird.min.js"></script>
<script>
    var promise = fetch("some url");

   promise.finally(...); 
</script>

ألا يجب أن يعمل هذا بشكل جيد لأنني قمت بتضمين Bluebird الذي حل محل التنفيذ الأصلي Promise ؟

أخيرًا ، إذا كنت أقوم بهذا الاستبدال الشامل الكامل في وقت التشغيل ، فيجب أن أكون قادرًا على إبلاغ TypeScript بهذا الأمر حتى يتم استبدال Bluebird أيضًا في وقت الترجمة.

ماذا ينقصني؟

إذا كنت تستخدم إصدار dist من بلوبيرد (وهو ما تفعله) ، فستستخدم مكتبات الجهات الخارجية Bluebird ، نظرًا لأن الوعد العالمي أصبح الآن Bluebird. تحصل على هذا الجزء بشكل صحيح. يذكر الناس خلاف ذلك ، لأنهم يتحدثون عن استخدام node.js لـ Bluebird.

هذا الموضوع برمته يدور حول الطريقة غير الواضحة لجعل الملخصات تتراكم مع هذا الافتراض (أن الوعد العالمي هو Bluebird). إذا تمكنت من القيام بذلك (على سبيل المثال من خلال declare global {} الشيء) ، تكون قد انتهيت.

@ d-ph لكن الوجبات الجاهزة هي أنني يجب أن أفعل ذلك في كل ملف *.ts بدلاً من مرة واحدة - هل هذا صحيح؟ ربما يكون من الجيد تلخيص "الحل" النهائي لهذه المشكلة. :)

نعم ، كما ترى ، لا يوجد حل بسيط من النوع just copy&paste this line to your X file and everyone and their dog are happy now هنا. أو على الأقل لست على علم بذلك.

آخر مرة راجعتك إما:

  1. انسخ والصق سطر import * as Bluebird from 'bluebird'; declare global { export interface Promise<T> extends Bluebird<T> {} } في كل ملف * .ts أو
  2. لف كل وعد تم إرجاعه من كود طرف ثالث في وظيفة مُنشئ Bluebird. في وقت التشغيل ، لن يفعل شيئًا (باستثناء النفقات الإضافية غير الضرورية لوقت التشغيل) وفي وقت الترجمة سيجعل TS سعيدًا.

مرة أخرى ، يتطلب الحل 1. وضع هذا الرمز في ملفات نقطة الإدخال فقط ، وليس كل ملف. على الأقل ، هذا ما نجح بالنسبة لي (webpack + awesome-typecript-loader).

إذا وجدت حلاً آخر يتطلب حرفياً من المطورين وضع سطر واحد فقط في ملف واحد ، فيرجى مشاركته مع المجتمع ؛ p

شكرًا @ d-ph - هل يمكنك تأكيد ما تقصده بعبارة "كل ملف نقطة دخول * .ts"؟

بلى. ملف "Entry point" .ts هو ملف .ts ، الذي تقوم بتحميله في html عبر علامة <script> . بمعنى آخر ، هذا هو الملف الذي يبدأ منه التجميع.

بعد البحث السريع في Google الآن ، وجدت هذا (لا تهتم بقراءته). خلاصة القول ، إذا أضفت global { export interface Promise<T> extends Bluebird<T> {} } يدويًا في bluebird.d.ts ، فلن تحتاج إلى ذكر هذا مرة أخرى في أي مكان آخر. ليس لدي وقت لاختباره في الوقت الحالي ، لكنني قمت باختباره باستخدام اختبار github repo الذي قمت بإنشائه ، ويبدو أنه يعمل.

بمعنى آخر ، قم بتنزيل Bluebird.d.ts وقم بتغيير هذا:

// Generated by typings
// Source: bluebird.d.ts
declare module 'bluebird' {
// Type definitions for Bluebird v3.x.x
// Project: http://bluebirdjs.com

class Bluebird<R> implements Bluebird.Thenable<R>, Bluebird.Inspection<R> {

الى هذا:

// Generated by typings
// Source: bluebird.d.ts
declare module 'bluebird' {
// Type definitions for Bluebird v3.x.x
// Project: http://bluebirdjs.com

global { export interface Promise<T> extends Bluebird<T> {} }

class Bluebird<R> implements Bluebird.Thenable<R>, Bluebird.Inspection<R> {

من الواضح أن هذا ليس مثاليًا ، خاصةً إذا كنت تستخدم @types/bluebird (والذي ستحتاج إلى إزالته الآن ، لأنك ستستخدم Bluebird.d.ts المخصص) ، ولكن حسنًا ...

إذن لدي بالفعل ملف _stubs.d.ts أضفت إليه ما يلي ، وأنا أقرب كثيرًا. لا مزيد من الشكاوى حول finally غير موجود في Promise ، لكن لسبب ما ، ما زلت أتلقى أخطاء حول delay غير موجودة في Promise . لم يكن علي تعديل bluebird.d.ts . سوف تحقق ولكن هذا قد يكون حلا رائعا!

declare module "bluebird-global" {
    import * as Bluebird from "bluebird";

    global { export interface Promise<T> extends Bluebird<T> { } }
}

تحرير: كانت مشكلتي مع delay لأنني كنت أتصل به بشكل ثابت ، على سبيل المثال Promise.delay(2000) .

من خلال الحل الذي نشرته أعلاه ، أتلقى هذا الخطأ عندما ترجع وظيفتي Promise<T> :

خطأ TS2322: اكتب "بلوبيرد'غير قابل للتخصيص لكتابة' Promise".

أعتقد أن هذا لأنني الآن قد استبدلت Promise بـ Bluebird ، عندما أستخدم then ، وما إلى ذلك ، فإن القيمة المرتجعة هي Bluebird<T> بدلاً من ذلك من Promise<T> .

ها هي النسخة الأخيرة من هذا الاختراق. لا أحب القيام بذلك ولكني أحبه أفضل من الخيارات الأخرى. بشكل أساسي ، لا بد لي من إعادة تكرار الأشياء التي أستخدمها على الواجهة ، وتغيير نوع الإرجاع إلى Promise بدلاً من Bluebird . هذه نسخة مباشرة ولصق من ملف تعريف Bluebird بخلاف ذلك.

_stubs.d.ts

declare module "bluebird-global" {
    import * as Bluebird from "bluebird";

    global {
        export interface Promise<T> extends Bluebird<T> {
            then<U1, U2>(onFulfill: (value: T) => U1 | Bluebird.Thenable<U1>, onReject: (error: any) => U2 | Bluebird.Thenable<U2>): Promise<U1 | U2>;
            then<U>(onFulfill: (value: T) => U | Bluebird.Thenable<U>, onReject: (error: any) => U | Bluebird.Thenable<U>): Promise<U>;
            then<U>(onFulfill: (value: T) => U | Bluebird.Thenable<U>): Promise<U>;
            then(): Promise<T>;

            finally<U>(handler: () => U | Bluebird.Thenable<U>): Promise<T>;
        }
    }
}

سيكون من الرائع أن يكون لديك تعريف رسمي bluebird-global أو bluebird-override يشبه إلى حد كبير التعريف الحالي ولكنه يستخدم Promise في كل مكان بدلاً من Bluebird .

سعيد لأنك تمكنت من إيجاد حل.

فقط من أجل الاكتمال: كما قال ProTip ، باستخدام JustWorksTM bluebird-2.0.d.ts . فقط قم بتثبيته بـ npm install @types/[email protected] وأضفه إلى tsconfig.json compilerOptions.types :

{
    "compilerOptions": {
//     (...)
        "types": [
          "bluebird"
        ]
    },
    "include": [
        "src/**/*.ts"
    ]
}

أي اختلافات بين ذلك d.ts وإصدار Bluebird الحالي (أي 3.x) أوصي بالاختراق يدويًا.

بواسطة JustWorksTM أعني: إنه يعمل من أجل:

أ) es5 الهدف
ب) es6 الهدف
ج) الهدف es5 مع core-js lib

بغض النظر عما إذا كان شخص ما يستخدم إعداد البناء (webpack + awesome-typecript-loader) أم لا. بالإضافة إلى ذلك ، لا يتم الخلط بين PhpStorm IDE على الإطلاق.

لقد قضيت بعض الوقت اليوم في النظر في هذه المشكلة ، وفي الواقع قمت بإنشاء / تحديث هاتين التذكرة في Microsoft / TypeScript: https://github.com/Microsoft/TypeScript/issues/10178 و https://github.com/Microsoft/TypeScript / قضايا / 12382 . فكرتي هي ، كما قلت (والبعض قبلك) ، أننا بحاجة إلى ملف bluebird-global.d.ts . لتجنب تكرار الكود ، وجدت أن هذا سيعمل:

// bluebird-global.d.ts

import * as Bluebird from "bluebird";

export as namespace Promise;
export = Bluebird;

شريطة حل التذكرتين المذكورتين أعلاه أو العثور على حلول بديلة. في غضون ذلك ، أوصي باستخدام Bluebird-2.0.d.ts ، عند الترميز للمتصفح.

تضمين التغريدة

كيف يمكن أن يكون هذا ، عندما يكون كود الطرف الثالث في مرحلة ما يستدعي مُنشئ الوعد (الوعد الجديد (...)) الذي تم استبداله بتنفيذ Bliebird على المستوى العالمي؟

سهل جدا. جرب في وحدة تحكم المتصفح (يفضل Chrome):

var NativePromise = Promise;
window.Promise = function() {}; // try to overload NativePromise
NativePromise === Promise; // false. Seems it is overloaded!
// And now, let check with some native code, which return Promise, for example fetch
Object.getPrototypeOf(fetch("")) === Promise.prototype; // false, Whoops!
Object.getPrototypeOf(fetch("")) === NativePromise.prototype; // true! Double whoops!

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

global ['Promise'] = يتطلب ('bluebird')

سيحل هذا محل كائن الوعد العالمي للتطبيق وجميع المكتبات المضمنة.

أهلا يا أصدقاء،

@types/bluebird-global متاح الآن. تستخدم هذه الكتابة @types/bluebird@^3.0 تحت غطاء محرك السيارة وتسمح لك باستخدام أساليب Bluebird على Promise العالمية (أي أن تجميع TS لا يفشل).

يرجى قراءة هذا لمعرفة كيفية استخدامه.

رائع ، شكرًا @ d-ph!

@ d-ph شكرًا على @types/bluebird-global . هل أحتاج إلى القيام بأي نوع من الاستيراد وإعادة التعيين في مشروعي لاستخدام بلوبيرد كبديل للوعد العالمي؟

npm install --save-dev @types/bluebird-global ثم اتبع التعليمات التي قمت بتضمينها في الكتابة: الرابط (تم تحديث الرابط 2017-04-02). هذا وحده من شأنه أن يفي بالغرض (على سبيل المثال ، يجب عدم الحاجة إلى عمليات استيراد / إعادة تعيين يدوية).

كملاحظة جانبية: لست بحاجة إلى ذكر @types/bluebird في package.json::devDependencies بعد الآن ، لأن هذا يعني ضمنيًا تلقائيًا.

تحديث للربط في التعليق السابق: رابط

MichaelTontchev @ d-ph هل هناك فرصة للحصول على واجهة Promise.Inspection المضافة إلى Bluebird-global ؟

مرحبًاksnyde.

يرجى التحدث معي. أنا المشرف.

هل يمكن أن تؤكد أنك تشير إلى هذا الوعد ، فهل تريد الفحص؟

يتم عرض جميع الطرق من تلك الواجهة عبر bluebird-global . أي ما يلي سيتم تجميعه:

let promiseInspectionTest = new Promise<void>((resolve) => {});
promiseInspectionTest.value();

لذلك يبدو لي أنك تطلب كشف هذا على أنه Promise.Inspection من bluebird-global .

هل يمكن أن تخبرني ، ما إذا كانت هذه نكسة كبيرة بالنسبة لك لاستخدام ما يلي بدلاً من ذلك:

import * as Bluebird from "bluebird";

class Foo<T> implements Bluebird.Inspection<T> {

}

نظرًا لأنك تستخدم bluebird-global ، يمكنك أيضًا استيراد الكتابة الأصلية bluebird بهذا الشكل بدون أي devDependencies صريح.

أفضل عدم تمديد Promise العالمي أكثر من ذلك بدون أسباب قوية وراء ذلك ، لأنه فن دقيق لجعل تلك الكتابة تعمل مع كتابة الوعد القياسية من lib.d.ts . أوصي حقًا بالوصول إلى هذه الواجهة من كتابات bluebird مباشرة ، لأن معلمي JavaScripts في يوم من الأيام قد يضيفون Promise.Inspection إلى المعيار ، مما قد يؤدي إلى كسر الكتابة bluebird-global ، مما يؤدي إلى يسبب مشاكل غير ضرورية للمستخدمين النهائيين.

أيضًا ، حتى إذا كنت سأضيف الواجهة ، فستحتاج إلى الانتظار مقدارًا غير محدد من الوقت حتى يتم دمجها في master ، لأن مشرفين DT مشغولون نوعًا ما مع العلاقات العامة هذه الأيام.

هتافات.

لقد كنت بالفعل أستخدم النهج الذي ناقشته في الوقت الحالي وهو عمل مناسب. أو ربما يكون "حل بديل" هو التسمية الخاطئة.

كنت أفهم / تصوري أن الفكرة وراء بلوبيرد جلوبال كانت الكشف عن مجموعة شاملة من وظائف الوعد التي يوفرها بلوبيرد في هذه الحالة كمستخدم أتوقع أن يتم الكشف عن Bluebird.Inspection عند Promise.Inspection . ومع ذلك ، إذا كان هدفك هو التأكد من أن سطح API الرسمي لـ Promises يستخدم Bluebird ، فأعتقد أن هذا "الحل البديل" هو في الواقع حل مناسب طويل المدى.

بينما أفضل تفسيري سأكون بخير باستخدام الحل المقدم هنا إذا لزم الأمر.

بينما أرى بالتأكيد من أين أتيت بتوقعاتك ، فإن السبب الرئيسي وراء إنشاء bluebird-global هو السماح لـ TypeScript بمعرفة ، أن الوعود التي تم إنشاؤها وإعادتها من كود طرف ثالث هي في الواقع أمثلة على وعود Bluebird ، والتي لم يكن هناك بديل آخر _ ليس مزعجًا_ ، ولكن لفضح كل مثيل Bluebird وطرقه الثابتة على رمز الوعد العالمي. كما ذكرت سابقًا ، فإن الطريقة التي يتم بها ذلك ليست بسيطة class Promise<T> extends Bluebird<T> {} (على الرغم من أنها كانت في الأصل) ، ولكنها بالأحرى رمز وعد عالمي مصحح بعناية. وكما ذكرت ، أفضل تجنب الاضطرار إلى الاحتفاظ بأي شيء ، يوجد بديل معروف له ، لا يجعلك حرفيًا تشد شعرك من رأسك.

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

هتافات.

من المنطقي. شكرا على التفكير وراء نهجك.

@ d-ph يفعل ما يلي أي معنى بالنسبة لك ... أتلقى خطأ يفيد بأن "عكس" ليس وظيفة في الكود أدناه:

image

وأثناء وجوده في intelisense للمحرر ، فإنه يحدد بشكل صحيح أن الخاصية p في وظيفة التعيين هي وعد Bluebird ولديها سطح API ممتد لا يوجد إلا في Bluebird (مقابل Promise).

image

أنا فقط لا أستطيع إخراج الرؤوس أو ذيولها. لقد لاحظت أنه عندما قمت بفحص _type_ لمتغير مكرر الخريطة ، فإنه يظهر على النحو التالي:

image

افترضت أن هذا هو سبب حصولي على سطح API المحدود المحدد بواسطة bluebird-global لكنني لا أعرف لماذا لا يتم حله بشكل صحيح.

مرحبا.

لا يمكنني إعادة الإنتاج: / تعمل مقتطفات الشفرة هذه في الإعداد الخاص بي.

أولا. أنت لا تستخدم bluebird-global في دالة allSettled() . تكتب مباشرةً باستخدام Bluebird . هذه ليست مشكلة ، لكن ربما لم تكن على علم بها. يستخدم المقتطف التالي bluebird-global :

function allSettled<T>(promises: Array<Promise<T>>) {
    const reflections = Promise.all<T>(promises.map((promise => {
        return promise.reflect();
    })));

    return reflections;
}

أي أن هذا المقتطف ينتقل إلى Promise العالمي (والذي تم تصحيحه باستخدام أساليب Bluebird في bluebird-global.d.ts ). كما قلت: هذا لمعلوماتك ، في حال لم تكن على علم به ، لأن مقتطفاتك ومقتطفاتي تعملان بنفس الطريقة.

لنعد إلى مشكلة فقدان أساليب Bluebird. تخميني هو: لا يمكنك استبدال Promise العالمي بـ Bluebird في وقت التشغيل ثم تقوم بتشغيل allSettled() مع الوعود التي تم إنشاؤها باستخدام الوعد العالمي بدلاً من Bluebird.

اسمحوا لي أن أريكم الكود الخاص بي وبعض لقطات الشاشة.

function allSettled<T>(promises: Array<Promise<T>>) {
    const reflections = Promise.all<T>(promises.map((promise => {
        return promise.reflect();
    })));

    return reflections;
}

let promises = [
    Promise.resolve(),
    Promise.reject(new Error("rejected test")),
    new Promise<void>(() => {}),
];

let reflections = allSettled(promises);

console.log(reflections);
// this is part of my entry point

/*
 * Promise
 */
import * as Promise from 'bluebird';
import 'expose-loader?Promise!bluebird';

image
_Pic 1: الوعد في Array.map () هو Bluebird (يمكنك معرفة ذلك من خلال وجود خصائص الشرطة السفلية مثل: _bitField ) _

image
_Pic 2: الوعد. انعكاس محدد بالفعل في الحلقة_

هل يمكنك تعيين نقطة توقف js مثلي في Chrome Dev Tools ، ومعرفة ما هو promise داخل .map ؟ الأفضل من ذلك: هل يمكنك كتابة Promise في وحدة التحكم ومعرفة ما إذا كنت ستحصل على الناتج التالي:
image

إذا حصلت على الناتج التالي ، فلن تستبدل Global Promise بـ Bluebird في وقت التشغيل:
image

في هذه الحالة عليك القيام بذلك. على سبيل المثال مثلي في ملف الدخول الخاص بك.

أخيرًا ، القليل من تعليقات المطورين: سأستخدم شخصيًا Promise<T>[] بدلاً من Array<Promise<T>> . لكن هذا يرجع إلى تفضيل المطورين بالطبع. لقد جئت للتو من خلفية C ، حيث لا يوجد قالب وحيث يستخدم المطورون عامل الوصول إلى الصفيف لتحديد الأنواع.

هتافات.

شكرا جزيلا لمثل هذا الشرح الشامل. هناك شيء واحد لم أكن متأكدًا منه رغم ذلك وهو ما الذي تشير إليه النقطة التالية:

استيراد "كشف محمل؟ وعد! بلوبيرد" ؛

@ d-ph ahhh ، كانت الخطوط الملاحية المنتظمة أعلاه هي ما كنت في عداد المفقودين. ما كنت لأصل إلى هناك بدون مساعدتك! قد أكون أنا فقط ولكني أعتقد أنه سيكون من المفيد إذا كان النص README يشير إلى استخدام Expose Loader .

على الرغم من أن نكون منصفين ، إلا أنني ما زلت لست 100٪ إذا كان هذا يتطلب استخدام حزمة الويب؟ هدفي ليس المتصفح ، بل مجرد وظيفة عقدة.

في الواقع ، يبدو أنه لا يعمل بشكل كامل لأنني أتلقى الخطأ التالي عندما أحاول تنفيذ الملف (لا توجد أخطاء في المحرر قبل وقت التشغيل):

خطأ: لا يمكن العثور على الوحدة النمطية "expose-loader؟ Promise! bluebird"

أنت محق ، expose-loader شيء webpack (محمل webpack). لذلك إذا لم تدع حزمة الويب تعالج عبارة import ، فلن يتم تشغيلها (على سبيل المثال ، ستحصل على الخطأ "لا يمكن العثور على وحدة").

إذا كنت لا تستطيع / لا تستخدم حزمة الويب ، فستحتاج إلى إيجاد طريقة أخرى لجعل الوعد العالمي يكون بلوبيرد في وقت التشغيل. ليس لدي خبرة كبيرة مع العقدة ، لكنني وجدت هذا الآن: https://github.com/petkaantonov/bluebird/issues/1026 (تجاوز Promise في العقدة).

أوصي بمعرفة كيفية استخدام عدم التزامن / انتظار في أحدث عقدة 7. أنت محظوظ بما يكفي للعيش في الأوقات ، عندما يكون هذا متاحًا للمطورين.

فيما يتعلق بذكر استخدام expose-loader في README: لقد ذكرت بالفعل في الجزء العلوي من ملف d.ts ، أن هذه مهمة devs لاستبدال Promise بـ Bluebird في وقت التشغيل: link . نظرًا لوجود العديد من الطرق للقيام بذلك ، لم أذكر أيًا منها في الواقع. ضع في اعتبارك أن expose-loader ما يعادل فقط تشغيل window.Promise = Bluebird . حسنًا ، آمل أن يقوم Google بفهرسة ردي ، لذلك لن يبحث الناس عن الخيارات الممكنة لفترة طويلة بعد الآن ؛ ص

@ d-ph يتطلع إلى الانتظار غير المتزامن الأصلي ولكن كل هذه الوظائف موجودة على AWS Lambda لذا فأنا مقفل على العقدة 6.10.x في الوقت الحالي. في تمرير مستقبلي لهذه الوظائف ، من المحتمل أن أقوم بالتبديل إلى غير متزامن في انتظار على أي حال ولدي نسخة مطبوعة من الكتابة إلى ES2015 ولكن لا أريد تقديم هذا حتى الآن.

على أي حال ، شكرًا على الرابط @ d-ph ، سأجرب هذا النهج. أوه ، وفي حال كان أي شخص مهتمًا بالنسخة النهائية من هذه الوظائف (والتي تعد مفيدة جدًا في أرض الوعد):

export function allSettled<T>(promises: Array<Promise<T>>) {
  const reflections = Promise.all<Promise.Inspection<T>>( promises.map((p => p.reflect())) );
  return reflections as Promise<Array<Promise.Inspection<T>>>;
}

export function settleProps<T>(promiseHash: IDictionary<Promise<T>>) {

  const reflections: IDictionary<Promise<Promise.Inspection<T>>> = Object.keys(promiseHash)
    .reduce((newObject: IDictionary<any>, key: string) => {
      newObject[key] = promiseHash[key].reflect();
      return newObject;
    }, {} as IDictionary<Promise<Promise.Inspection<T>>>);

  return Promise.props(reflections) as Promise<IDictionary<Promise.Inspection<T>>>;
}

تتوفر معلومات كاملة من نوع intelisync وهو أمر رائع للغاية.

@ d-ph آمل أن يكون الأمر على ما يرام إذا أحيت هذا بسؤال ذي صلة ...

عندما أحاول استخدام بلوبيرد جلوبال ، يبدو أنني أتعرض لبعض الاختلافات في التعريف في كل من then و catch . أرى أنه يتم التعامل مع هؤلاء بشكل خاص في Bluebird-global ، ولكن يبدو أنه يقصرني على Promise api القياسي بدلاً من الحصول على بلوبيرد. فمثلا:

Promise.resolve(true).catch(Error, () => false)

فشل نظرًا لأن catch يتوقع وسيطة واحدة فقط.

ومسألة أخرى:

Promise.resolve([3]).map((n: number) => true)

فشل مع:

│TS2345: Argument of type '(n: number) => boolean' is not assignable to parameter of type 'IterateFunction<{}, boolean>'.           │
│  Types of parameters 'n' and 'item' are incompatible.                                                                             │
│    Type '{}' is not assignable to type 'number'.                                                                                  │

هل يجب أن يعمل هؤلاء أم أفعل شيئًا خاطئًا؟ إنهم يعملون في وقت التشغيل ، ولا يقومون بفحص الكتابة.

شكرا!

مرحبا،

حول .catch(Error, function) ، أنت محق بقولك أن .then ، .catch (وأكثر) يتم التعامل معها بشكل مختلف عن باقي وظائف Bluebird. ومع ذلك ، يتم تضمين تجاوز .catch(Error, function) المحدد في بلوبيرد جلوبال. لقد راجعت مرة أخرى وأنا قادر على تجميع:

Promise.resolve(true).catch(Error, () => false)

راجعت مع TS 3.0.1 و 2.9.2. لا أعرف لماذا قد تواجه مشكلة هنا. ربما هناك شيء محدد في مشروع TS الخاص بك يتجاوز الوعد العالمي بعد bluebird-global . انا لا اعرف. ربما تحاول تضييق نطاق سبب المشكلة من خلال البدء من مشروع TS أساسي جدًا ثم إضافة المزيد من التبعيات من مشروعك الحالي ، ومعرفة النقطة التي تنقطع فيها.

حول المشكلة الأخرى: لا أعرف لماذا لا يعمل. ونعم ، يجب أن يعمل. الرجاء إنشاء مشكلة github لذلك وسنبدأ من هناك. فيما يلي بعض الحقائق عن المشكلة:

  1. كل ما يفعله bluebird-global مع .map() يعيد استخدام تعريف النوع bluebird.d.ts .map() . بمعنى آخر ، لا ينبغي أن يأتي العيب من كتابات bluebird-global .
  2. فشل السطر الذي ذكرته في Promise.map() ، لكنه يعمل على Bluebird.map() :
import Bluebird = require('bluebird');

Bluebird.resolve([3]).map((n: number) => true); // works

Promise.resolve([3]).map((n: number) => true); // fails
  1. بعد قضاء بعض الوقت في فك تشفير مشكلة الطباعة (بشكل أساسي: لماذا استنتج TS أن المعلمة n يجب أن تكون {} ) ، استنتجت أن bluebird.d.ts أيضًا لا يجب أن تعمل ، لكنها تعمل لسبب غير معروف بالنسبة لي. قصة قصيرة طويلة ، ما يلي هو ما تمت كتابة .map() إليه بعد إزالة جميع طبقات التجريد:
map<U>(
    mapper: (
        item: U,
        index: number,
        arrayLength: number
    ) => U | PromiseLike<U>,
    options?: Bluebird.ConcurrencyOption
): Bluebird<T extends Iterable<any> ? U[] : never>;

تقول أن نوع الإرجاع للوظيفة mapper يجب أن يكون هو نفسه (أو وعد من نفس النوع) مثل نوع item . في المثال الخاص بك ، نوع العنصر هو number ونوع الإرجاع هو boolean . أنا غير قادر على فهم سبب هذا التحويل البرمجي عند استخدام Bluebird مباشرة ، لكنه لا يحدث عند استخدام الوعد العالمي. بالمناسبة ، ما زال لا يعمل ، عندما أقوم بتغيير نوع الإرجاع في مثالك ليكون أي رقم. ومع ذلك ، فإنه يعمل عندما أقول أن item يمكن أن يكون من النوع any . هناك خطأ ما في bluebird.d.ts type IterableItem<R> واستخدامه في هذا السياق.

@ د-ف


تعديل:

تحققت من نموذج map() "بدون طبقات" مرة أخرى ، ولم تتم كتابة الوظيفة mapper للحصول على نفس نوع الإرجاع مثل نوع item (اعتقدت ذلك كنت). خطأي.

كل ما يفعله bluebird-global مع .map () هو إعادة استخدام تعريف نوع map () الخاص بـ bluebird.d.ts.

هل المشكلة هي أنه عند نسخ النوع من الفئة العامة Bluebird<R> ، يتم تعيينه افتراضيًا على {} لـ R لأنه لا يمكنه الاستدلال عليه من الوالد؟

أتساءل ما إذا كان map: typeof Bluebird<T>.prototype.map سيعمل؟ (لم أجرب هذا بعد)

الأهمية:
إذا كنت تستخدم @types/bluebird-global ، فاحذف النموذج @types/bluebird كما قال @ d-ph

npm install --save-dev @types/bluebird-global ثم اتبع التعليمات التي قمت بتضمينها في الكتابة: الرابط (تم تحديث الرابط في 2017-04-02). هذا وحده من شأنه أن يفي بالغرض (على سبيل المثال ، يجب عدم الحاجة إلى عمليات استيراد / إعادة تعيين يدوية).

كملاحظة جانبية: لست بحاجة إلى ذكر @types/bluebird في package.json::devDependencies بعد الآن ، لأن هذا يعني ضمنيًا تلقائيًا.

تسبب كلاهما في حدوث تطابق خاطئ بين الأنواع التي تعود @types/bluebird ووعدي العالمي ( @types/bluebird-global )

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

jgoz picture jgoz  ·  3تعليقات

victor-guoyu picture victor-guoyu  ·  3تعليقات

tyv picture tyv  ·  3تعليقات

JWT
svipas picture svipas  ·  3تعليقات

fasatrix picture fasatrix  ·  3تعليقات