2016-09-27 3 views
1

Я работаю над приложением, которое использует what-wg для извлечения по всему месту. Мы определены по умолчанию выборки ЕГО и опционам так:Определить запасной улов для цепочки обещаний?

export function fetchMiddleware(response) { 
    return new Promise(resolve => { 
    resolve(checkStatus(response)); 
    }).then(parseJSON); 
} 

export const fetchDefaults = { 
    credentials: 'same-origin', 
    headers: { 
    'Accept': 'application/json', 
    'Content-Type': 'application/json' 
    } 
}; 

Мы используем по умолчанию промежуточного программного обеспечения/Fetch опционов так:

fetch('/api/specific/route', fetchDefaults) 
    .then(fetchMiddleware) 
    .then(function(data) { 
    // ... Dispatch case-specific fetch outcome 
    dispatch(specificRouteResponseReceived(data)); 
    }); 

Мы хотим, чтобы добавить общий, резервный улов всех fetch Обычаи по всему приложению, другими словами, что-то вроде этого:

export function fetchGenericCatch(function(error) { 
    showGenericErrorFlashMessage(); 
}) 

fetch('/en/api/user/me/preferences', fetchDefaults) 
    .then(fetchMiddleware) 
    .then(function(data) { 
    dispatch(userPreferencesReceived(data)); 
    }) 
    .catch(fetchGenericCatch); 

много дублирования кода. Нам нужна функция/класс utility, которая может сделать все это для нас, например. то, что будет работать так:

genericFetch('/api/specific/route') // bakes in fetchDefaults and fetchMiddleware and fetchGenericCatch 
    .then(function(data) { 
    dispatch(userPreferencesReceived(data)); 
    }); // gets generic failure handler for free 

genericFetch('/api/specific/route') // bakes in fetchDefaults and fetchMiddleware and fetchGenericCatch 
    .then(function(data) { 
    dispatch(userPreferencesReceived(data)); 
    }) 
    .catch(function(error) { 
    // ... 
    }); // short-circuits generic error handler with case-specific error handler 

Основной нюанс в том, что общий catch должен быть прикован после в случае конкретных then с/catch эс.

Любые советы о том, как это может быть достигнуто с помощью whatwg-fetch/ES6 Promises?

Связанные:

Есть аналогичные должности, но они, кажется, не рассмотреть вопрос о необходимости улова по умолчанию, который работает после всех нестандартных then с и catch ов:

Редактировать 14 октября:

Возможный дубликат: Promises and generic .catch() statements

+0

Правильно ли я понимаю вас, что вы хотите добавить прослушиватель '.catch' автоматически, даже если пользователь добавил' .then/.catch'es после того, как ваша функция вернулась? Это невозможно AFAIK. – nils

+0

Нет, я хочу добавить обещание по умолчанию 'catch', которое будет обрабатывать любые неперехваченные ошибки --- если ошибка применима --- если обработчик' catch' не был определен иначе. –

ответ

0

Имея WET код не самый худший вариант здесь, до тех пор, поскольку обработчик ошибок DRY.

fetch(...) 
... 
.catch(importedFetchHandler); 

Это не вызывает никаких проблем и соответствует поведению Bluebird и V8 обещаний, где существует необработанное событие отвержения, чтобы убедиться, что никакие обещания не остались неперехваченными.


Самый простой способ достичь этого является введение обещание, как обертку для fetch обещание:

function CatchyPromiseLike(originalPromise) { 
    this._promise = originalPromise; 

    this._catchyPromise = Promise.resolve() 
    .then(() => this._promise) 
    .catch((err) => { 
    console.error('caught', err); 
    }); 

    // every method but 'constructor' from Promise.prototype 
    const methods = ['then', 'catch']; 

    for (const method of methods) { 
    this[method] = function (...args) { 
     this._promise = this._promise[method](...args); 

     return this; 
    } 
    } 
} 

, который может быть использован как

function catchyFetch(...args) { 
    return new CatchyPromiseLike(fetch(...args)); 
} 

обещание, как подобное имеет естественные ограничения.

Побочных эффекты отбрасываются, если преобразуются в реальное обещание:

Promise.resolve(catchyFetch(...)).then(() => /* won't be caught */); 

И это не будет хорошо играть с асинхронной цепью (это не является ни-ни для всех обещаний):

var promise = catchyFetch(...); 

setTimeout(() => { 
    promise.then(() => /* won't be caught */); 
}); 

Хорошей альтернативой является Bluebird, нет необходимости изобретать колесо там, функции - это то, ради чего его любят. Local rejection events выглядеть именно то, что нужно:

// An important part here, 
// only the promises used by catchyFetch should be affected 
const CatchyPromise = Bluebird.getNewLibraryCopy(); 

CatchyPromise.onPossiblyUnhandledRejection((err) => { 
    console.error('caught', err); 
}); 

function catchyFetch(...args) { 
    return CatchyPromise.resolve(fetch(...args)); 
} 

Уф, это было легко.

+0

Любовь к решению BlueBird 'onPossiblyUnhandledRejection'. Работает как шарм на JS Bin. По какой-то еще загадочной причине это не работает в нашей настройке Babel. Мы рассмотрим это отдельно :) Еще раз спасибо http://jsbin.com/rerafucoza/edit?js,console –

+0

Добро пожаловать. Обратите внимание, что только последние версии Bluebird поддерживают getNewLibraryCopy. – estus

+0

Да, мы также используем 3.4.6. Вызов функции существует и так далее. Тем не менее, никакого эффекта, очень странно! Ошибка не поймана, хотя код полностью соответствует JS Bin. Попробуйте различные пресетов и плагинов Babel, чтобы увидеть, как правильно вводить голубую птицу каким-то другим способом. В понедельник все может показаться яснее. –

0

Я думаю, что решение так просто, как:

export function genericFetch(url, promise, optionOverrides) { 
    const fetchOptions = {...fetchDefaults, ...optionOverrides}; 
    return fetch(url, fetchOptions) 
    .then(fetchMiddleware) 
    .then(promise) 
    .catch(function(error) { 
     showGenericFlashMessage(); 
    }); 
} 

Прецедент, который не нуждается в специальной ошибке обработчик может просто использовать его таким образом:

genericFetch('/api/url', function(data) { 
    dispatch(apiResponseReceived(data)); 
}); 

Прецедент, который необходим специальный фиксатор, или более сложную цепь, может перейти в полномасштабный обещание:

genericFetch('/api/url', function(response) { 
    return new Promise(resolve, reject => { 
    dispatch(apiResponseReceived(data)); 
    }).catch(nonGenericCaseSpecificCatch); // short-circuits default catch 
}); 
Смежные вопросы