我正在努力理解Javascript的承诺,到目前为止这就是我得到的。基本上我试图用setInterval和setTimeout来模拟ajax请求,以了解我如何使用:
promise.progress promise.done promise.fail promise.always promise.catch
下面的console.log()示例显示除fail和catch之外的所有内容。我不知道如何打破代码来触发失败?或者是失败的IS捕获?或者在失败后赶来?
你能帮助我以捕获和处理失败所需的所有方式破解这段代码吗?
$(document).ready(function() {
console.log('1. Document is ready.');
var timer;
var i = 1;
// Declare and Call the promise.
var promise = myProcess();
promise.progress(function() {
// Receives updates from deferred.notify();
// deferred.notify updates promise.progress on every Tick of timer = setInterval
console.clear();
console.log('promise.progress.. ' + i++);
});
promise.done(function() {
// deferred.resolve triggers at the end of setTimeout
console.log('promise.done');
});
promise.fail(function(error) {
// Executes on fail...
console.log('promise.fail');
});
promise.always(function() {
// Executes always...
console.log('promise.always');
//console.log(myProcess());
});
function myProcess() {
var deferred = $.Deferred();
timer = setInterval(function() {
// Tick every 1 second...
deferred.notify();
}, 1000);
// until the 3rd second...
setTimeout(function() {
clearInterval(timer);
deferred.resolve();
}, 3000);
return deferred.promise();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
我建议阅读一些关于承诺的文章。那些将能够比我更好地解释方式。还尝试在现代浏览器上使用“真正的”承诺。否则,一旦你离开JQuerys deferred(),你将不得不重新学习一些东西,因为它是一个非标准的promises实现,所以API会有所不同。但是,让我们看看我们可以用你的代码做些什么。
1)如果我们想要测试一个承诺的所有可能结果,我们需要在一个可能成功或失败的承诺中做一些事情。 ajax调用就是一个很好的例子。所以让我们创建一个可以工作的函数并稍微更改myProcess函数,以便对我们提供的uri进行ajax调用。
var myProcess = function myProcess( uri ) {
var deferred = $.Deferred();
// Keep the timer so the .progress() method will get triggered.
// In the example of an ajax call, you'd probably want to bind this to either the readystatechange event or to some work the callback of $.get() executes.
timer = setInterval(function() {
// Tick every 1 second...
deferred.notify();
}, 1000);
// Make an ajax call. If it suceeeds, resolve, else reject
// Since an ajax call is already async, we don't need to simulate the waiting with the timeout.
$.get( uri, function( data ) {
// remove the timer again once the ajax result returns.
clearInterval( timer );
if ( data ) deferred.resolve( data );
else deferred.reject( data );
} );
return deferred.promise();
};
2)使用myProcess函数并将一些处理程序链接到它。 .done()方法等同于标准Promises的.then()方法。
myProcess( 'http://some.api.uri/' )
// This will get triggered every second as long as the timer is active.
// If you want this to take longer for testing purposes, just make the ajax call take longer by adding a setTimeout again.
.progress( function onProgress() {
// The promise is still being resolved. Every second this gets triggered because we have deferred.notify() inside myProcess().
} )
// This will trigger once the ajax call succeeds succesfully and hence, .resolve() is triggered.
.done( function onResolved_1( data ) {
// Do something with the data you received from the ,get() call inside myProcess.
return JSON.parse( data );
} )
// This will trigger after the previous .done() function ( onResolved_1 ) has returned the data.
.done( function onResolved_2( dataReturnedFromPreviousDone ) {
// Do something with the data we parsed.
} )
// This will only trigger if the ajax call fails and hence, .reject() gets triggered.
.fail( function onFail( error ) {
// Do something with the error.
} )
// This will happen no matter if the promise gets resolved or rejected.
.always( function always() {
// stuff that always needs to happen.
} );
更新:本机承诺包裹在JQuery.get()
最后它非常简单。只要你有异步发生的事情,只需将它包装在一个承诺中,然后继续使用.then()
链接。因此,如果我们想宣传JQuery .get(),我们可以使用以下基本包装器:
var getURI = function getURI( uri ) {
// Wrap the basic $.get() function into a native promsie object.
// The promise constructor expects a function that will take in the resolve and reject methods as parameters
return new Promise( function( resolve, reject ) {
$.get( uri, function( data ) {
if ( data ) resolve( data );
else reject( new Error( 'could not load uri: ' + uri ) );
} );
} );
};
然后,我们可以使用该功能来抓住我们的东西。页面,数据,我们可以获得的任何东西。
var getData = function getData( callback ) {
// Do any work that you want to happen before the GET call
console.log( 'this always happens before we fetch the data' );
// Make the request for the data. Let's assume it returns us a text structured as JSON.
getURI( 'https://postman-echo.com/get?foo1=bar1&foo2=bar2' )
// .then() accepts two functions. One to trigger after resolve() and one to trigger after reject()
.then(
function onResolve( data ) {
// do something with the data
// If the only thing you do with the data is returning the result of a function, you don't have to wrap that function.
// So if we only want to parse, we can just use .then( JSON.parse )
return data;
},
function onReject( error ) {
// do something with the error.
console.log( 'error thrown inside onReject() after getURI failed to get data.' );
console.error( error );
}
} )
// Anything you return from inside the onResolve() function will get used as the parameter for the next onResolve() function in the chain.
.then( function( data ) {
// do something else.
// instead of using a callback, you could also return the promise and keep chaining from there.
callback( data );
} );
};
.then()
函数不要求您始终提供拒绝处理程序。如果您只想提供一个错误处理程序,可以在最后使用.catch()
。唯一真正缺少的是.progress()
方法。 .first()
是触发承诺之前的任何代码。
行动承诺的一个完整例子是:
var getURI = function getURI( uri ) {
return new Promise( function( resolve, reject ) {
$.get( uri, function( data ) {
if ( data ) resolve( data );
else reject( new Error( 'could not load uri: ' + uri ) );
} );
} );
};
var doThisFirst = function doThisFirst() {
console.log( 'this should be the first log to appear' );
};
var doThisLast = function doThisLast() {
console.log( 'this.should always be the last log' );
};
var addMeta = function addMeta( obj ) {
obj.meta = 'extra meta data';
return obj;
};
var renderData = function renderData( obj ) {
console.log( 'we received the following object and added a meta property to it: ' );
console.dir( obj );
};
var handleError = function handleError( error ) {
console.log( 'we found an error while fetching and augmenting some data' );
console.error( error );
};
var runApplication = function runApplication() {
doThisFirst();
getURI( 'https://postman-echo.com/get?foo1=bar1&foo2=bar2' )
.then( JSON.parse )
.then( addMeta )
.then( renderData )
.then( doThisLast )
.catch( handleError );
};
runApplication();